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