added i128 integer support
This commit is contained in:
		
							parent
							
								
									e30bd829aa
								
							
						
					
					
						commit
						28b9fed8e5
					
				|  | @ -36,6 +36,12 @@ impl Decode<'_> for isize { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Decode<'_> for i128 { | ||||
|     fn decode(d: &mut Decoder) -> Result<Self, Error> { | ||||
|         d.big_integer() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Decode<'_> for usize { | ||||
|     fn decode(d: &mut Decoder) -> Result<Self, Error> { | ||||
|         d.word() | ||||
|  |  | |||
|  | @ -35,6 +35,18 @@ impl<'b> Decoder<'b> { | |||
|         Ok(zigzag::to_isize(self.word()?)) | ||||
|     } | ||||
| 
 | ||||
|     /// Decode an integer of any size.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// First we decode the next 8 bits of the buffer.
 | ||||
|     /// We take the 7 least significant bits as the 7 least significant bits of the current unsigned integer.
 | ||||
|     /// If the most significant bit of the 8 bits is 1 then we take the next 8 and repeat the process above,
 | ||||
|     /// filling in the next 7 least significant bits of the unsigned integer and so on.
 | ||||
|     /// If the most significant bit was instead 0 we stop decoding any more bits.
 | ||||
|     /// Finally we use zigzag to convert the unsigned integer back to a signed integer.
 | ||||
|     pub fn big_integer(&mut self) -> Result<i128, Error> { | ||||
|         Ok(zigzag::to_i128(self.big_word()?)) | ||||
|     } | ||||
| 
 | ||||
|     /// Decode a single bit of the buffer to get a bool.
 | ||||
|     /// We mask out a single bit of the buffer based on used bits.
 | ||||
|     /// and check if it is 0 for false or 1 for true.
 | ||||
|  | @ -130,6 +142,28 @@ impl<'b> Decoder<'b> { | |||
|         Ok(final_word) | ||||
|     } | ||||
| 
 | ||||
|     /// Decode a word of any size.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// First we decode the next 8 bits of the buffer.
 | ||||
|     /// We take the 7 least significant bits as the 7 least significant bits of the current unsigned integer.
 | ||||
|     /// If the most significant bit of the 8 bits is 1 then we take the next 8 and repeat the process above,
 | ||||
|     /// filling in the next 7 least significant bits of the unsigned integer and so on.
 | ||||
|     /// If the most significant bit was instead 0 we stop decoding any more bits.
 | ||||
|     pub fn big_word(&mut self) -> Result<u128, Error> { | ||||
|         let mut leading_bit = 1; | ||||
|         let mut final_word: u128 = 0; | ||||
|         let mut shl: u128 = 0; | ||||
|         // continue looping if lead bit is 1 which is 128 as a u8 otherwise exit
 | ||||
|         while leading_bit > 0 { | ||||
|             let word8 = self.bits8(8)?; | ||||
|             let word7 = word8 & 127; | ||||
|             final_word |= (word7 as u128) << shl; | ||||
|             shl += 7; | ||||
|             leading_bit = word8 & 128; | ||||
|         } | ||||
|         Ok(final_word) | ||||
|     } | ||||
| 
 | ||||
|     /// Decode a list of items with a decoder function.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// Decode a bit from the buffer.
 | ||||
|  |  | |||
|  | @ -26,6 +26,14 @@ impl Encode for u8 { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Encode for i128 { | ||||
|     fn encode(&self, e: &mut Encoder) -> Result<(), Error> { | ||||
|         e.big_integer(*self); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Encode for isize { | ||||
|     fn encode(&self, e: &mut Encoder) -> Result<(), Error> { | ||||
|         e.integer(*self); | ||||
|  |  | |||
|  | @ -98,6 +98,19 @@ impl Encoder { | |||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// Encode an integer of any size.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// First we use zigzag once to double the number and encode the negative sign as the least significant bit.
 | ||||
|     /// Next we encode the 7 least significant bits of the unsigned integer. If the number is greater than
 | ||||
|     /// 127 we encode a leading 1 followed by repeating the encoding above for the next 7 bits and so on.
 | ||||
|     pub fn big_integer(&mut self, i: i128) -> &mut Self { | ||||
|         let i = zigzag::to_u128(i); | ||||
| 
 | ||||
|         self.big_word(i); | ||||
| 
 | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// Encode a char of 32 bits.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// We encode the 7 least significant bits of the unsigned byte. If the char value is greater than
 | ||||
|  | @ -152,6 +165,29 @@ impl Encoder { | |||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// Encode a unsigned integer of any size.
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// We encode the 7 least significant bits of the unsigned byte. If the char value is greater than
 | ||||
|     /// 127 we encode a leading 1 followed by repeating the above for the next 7 bits and so on.
 | ||||
|     pub fn big_word(&mut self, c: u128) -> &mut Self { | ||||
|         let mut d = c; | ||||
|         loop { | ||||
|             let mut w = (d & 127) as u8; | ||||
|             d >>= 7; | ||||
| 
 | ||||
|             if d != 0 { | ||||
|                 w |= 128; | ||||
|             } | ||||
|             self.bits(8, w); | ||||
| 
 | ||||
|             if d == 0 { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// Encode a list of bytes with a function
 | ||||
|     /// This is byte alignment agnostic.
 | ||||
|     /// If there are bytes in a list then write 1 bit followed by the functions encoding.
 | ||||
|  |  | |||
|  | @ -11,3 +11,17 @@ pub fn to_usize(x: isize) -> usize { | |||
| pub fn to_isize(u: usize) -> isize { | ||||
|     ((u >> 1) as isize) ^ (-((u & 1) as isize)) | ||||
| } | ||||
| 
 | ||||
| pub fn to_u128(x: i128) -> u128 { | ||||
|     let double_x = x << 1; | ||||
| 
 | ||||
|     if x.is_positive() || x == 0 { | ||||
|         double_x as u128 | ||||
|     } else { | ||||
|         (-double_x - 1) as u128 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn to_i128(u: u128) -> i128 { | ||||
|     ((u >> 1) as i128) ^ (-((u & 1) as i128)) | ||||
| } | ||||
|  |  | |||
|  | @ -122,7 +122,7 @@ where | |||
| #[derive(Debug, Clone, PartialEq)] | ||||
| pub enum Constant { | ||||
|     // tag: 0
 | ||||
|     Integer(isize), | ||||
|     Integer(i128), | ||||
|     // tag: 1
 | ||||
|     ByteString(Vec<u8>), | ||||
|     // tag: 2
 | ||||
|  |  | |||
|  | @ -310,7 +310,7 @@ fn encode_type(typ: &Type, bytes: &mut Vec<u8>) { | |||
| impl<'b> Decode<'b> for Constant { | ||||
|     fn decode(d: &mut Decoder) -> Result<Self, de::Error> { | ||||
|         match &decode_constant(d)?[..] { | ||||
|             [0] => Ok(Constant::Integer(isize::decode(d)?)), | ||||
|             [0] => Ok(Constant::Integer(i128::decode(d)?)), | ||||
|             [1] => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)), | ||||
|             [2] => Ok(Constant::String(String::decode(d)?)), | ||||
|             [3] => Ok(Constant::Unit), | ||||
|  | @ -354,7 +354,7 @@ impl<'b> Decode<'b> for Constant { | |||
| 
 | ||||
| fn decode_constant_value(typ: Type, d: &mut Decoder) -> Result<Constant, de::Error> { | ||||
|     match typ { | ||||
|         Type::Integer => Ok(Constant::Integer(isize::decode(d)?)), | ||||
|         Type::Integer => Ok(Constant::Integer(i128::decode(d)?)), | ||||
|         Type::ByteString => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)), | ||||
|         Type::String => Ok(Constant::String(String::decode(d)?)), | ||||
|         Type::Unit => Ok(Constant::Unit), | ||||
|  |  | |||
|  | @ -515,7 +515,7 @@ impl Value { | |||
|                 PlutusData::BigInt(i) => { | ||||
|                     if let BigInt::Int(g) = i { | ||||
|                         let numb: i128 = (*g).try_into().unwrap(); | ||||
|                         total += Value::Con(Constant::Integer(numb as isize)).to_ex_mem(); | ||||
|                         total += Value::Con(Constant::Integer(numb)).to_ex_mem(); | ||||
|                     } else { | ||||
|                         unreachable!() | ||||
|                     }; | ||||
|  |  | |||
|  | @ -37,9 +37,9 @@ pub enum Error { | |||
|     #[error("Decoding utf8")] | ||||
|     Utf8(#[from] FromUtf8Error), | ||||
|     #[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)] | ||||
|     ByteStringOutOfBounds(isize, Vec<u8>), | ||||
|     ByteStringOutOfBounds(i128, Vec<u8>), | ||||
|     #[error("Divide By Zero\n\n{0} / {1}")] | ||||
|     DivideByZero(isize, isize), | ||||
|     DivideByZero(i128, i128), | ||||
|     #[error("Ed25519S PublicKey should be 32 bytes but it was {0}")] | ||||
|     UnexpectedEd25519PublicKeyLength(usize), | ||||
|     #[error("Ed25519S Signature should be 64 bytes but it was {0}")] | ||||
|  |  | |||
|  | @ -349,7 +349,7 @@ impl DefaultFunction { | |||
|                     if *arg2 != 0 { | ||||
|                         let ret = (*arg1 as f64) / (*arg2 as f64); | ||||
| 
 | ||||
|                         Ok(Value::Con(Constant::Integer(ret.floor() as isize))) | ||||
|                         Ok(Value::Con(Constant::Integer(ret.floor() as i128))) | ||||
|                     } else { | ||||
|                         Err(Error::DivideByZero(*arg1, *arg2)) | ||||
|                     } | ||||
|  | @ -363,7 +363,7 @@ impl DefaultFunction { | |||
| 
 | ||||
|                         let ret = if ret < 0. { ret.ceil() } else { ret.floor() }; | ||||
| 
 | ||||
|                         Ok(Value::Con(Constant::Integer(ret as isize))) | ||||
|                         Ok(Value::Con(Constant::Integer(ret as i128))) | ||||
|                     } else { | ||||
|                         Err(Error::DivideByZero(*arg1, *arg2)) | ||||
|                     } | ||||
|  | @ -447,7 +447,7 @@ impl DefaultFunction { | |||
|             }, | ||||
|             DefaultFunction::LengthOfByteString => match &args[0] { | ||||
|                 Value::Con(Constant::ByteString(arg1)) => { | ||||
|                     Ok(Value::Con(Constant::Integer(arg1.len() as isize))) | ||||
|                     Ok(Value::Con(Constant::Integer(arg1.len() as i128))) | ||||
|                 } | ||||
|                 _ => unreachable!(), | ||||
|             }, | ||||
|  | @ -456,7 +456,7 @@ impl DefaultFunction { | |||
|                     let index = *arg2 as usize; | ||||
| 
 | ||||
|                     if 0 <= *arg2 && index < arg1.len() { | ||||
|                         let ret = arg1[index] as isize; | ||||
|                         let ret = arg1[index] as i128; | ||||
| 
 | ||||
|                         Ok(Value::Con(Constant::Integer(ret))) | ||||
|                     } else { | ||||
|  | @ -749,7 +749,7 @@ impl DefaultFunction { | |||
|                         Type::Integer, | ||||
|                         Type::List(Box::new(Type::Data)), | ||||
|                         // TODO: handle other types of constructor tags
 | ||||
|                         Box::new(Constant::Integer(convert_tag_to_constr(c.tag as isize))), | ||||
|                         Box::new(Constant::Integer(convert_tag_to_constr(c.tag as i128))), | ||||
|                         Box::new(Constant::ProtoList( | ||||
|                             Type::Data, | ||||
|                             c.fields | ||||
|  | @ -798,7 +798,7 @@ impl DefaultFunction { | |||
|                     if let BigInt::Int(i) = b { | ||||
|                         let x: i128 = (*i).try_into().unwrap(); | ||||
| 
 | ||||
|                         Ok(Value::Con(Constant::Integer(x as isize))) | ||||
|                         Ok(Value::Con(Constant::Integer(x))) | ||||
|                     } else { | ||||
|                         unreachable!() | ||||
|                     } | ||||
|  | @ -844,7 +844,7 @@ impl DefaultFunction { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fn convert_tag_to_constr(tag: isize) -> isize { | ||||
| fn convert_tag_to_constr(tag: i128) -> i128 { | ||||
|     if tag < 128 { | ||||
|         tag - 121 | ||||
|     } else if (1280..1401).contains(&tag) { | ||||
|  |  | |||
|  | @ -106,7 +106,7 @@ peg::parser! { | |||
|           = "(" _* "error" _* ")" { Term::Error } | ||||
| 
 | ||||
|         rule constant_integer() -> Constant | ||||
|           = "integer" _+ i:number() { Constant::Integer(i as isize) } | ||||
|           = "integer" _+ i:big_number() { Constant::Integer(i as i128) } | ||||
| 
 | ||||
|         rule constant_bytestring() -> Constant | ||||
|           = "bytestring" _+ "#" i:ident()* { | ||||
|  | @ -125,6 +125,9 @@ peg::parser! { | |||
|         rule number() -> isize | ||||
|           = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) } | ||||
| 
 | ||||
|         rule big_number() -> i128 | ||||
|           = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) } | ||||
| 
 | ||||
|         rule constant_data() -> Constant | ||||
|           = "data" _+ "#" i:ident()* { | ||||
|             Constant::Data( | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ use crate::ast::{Constant, Term}; | |||
| use crate::program_builder::WithTerm; | ||||
| 
 | ||||
| pub trait WithConstant: WithTerm { | ||||
|     fn with_int(self, int: isize) -> Self::Next { | ||||
|     fn with_int(self, int: i128) -> Self::Next { | ||||
|         let term = Term::Constant(Constant::Integer(int)); | ||||
|         self.next(term) | ||||
|     } | ||||
|  | @ -42,7 +42,7 @@ mod tests { | |||
|     proptest! { | ||||
|         #[test] | ||||
|         fn build_named__with_const( | ||||
|             int: isize | ||||
|             int: i128 | ||||
|         ) { | ||||
|             let code = format!(r"(program
 | ||||
|                            11.22.33 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 alessandrokonrad
						alessandrokonrad