From 9ef06ef0280265432b7e2b1fd82492dd041c0aef Mon Sep 17 00:00:00 2001 From: Christian Lewe Date: Fri, 27 Sep 2024 14:02:57 +0200 Subject: [PATCH] feat: Decode value from compact / padded encoding Decode a Simplicity value as an associated method of the Value struct. Differentiate between compact and padded encoding. --- jets-bench/src/data_structures.rs | 2 +- src/bit_encoding/bititer.rs | 55 +----------- src/bit_machine/mod.rs | 9 +- src/human_encoding/parse/ast.rs | 4 +- src/node/redeem.rs | 2 +- src/value.rs | 133 ++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 61 deletions(-) diff --git a/jets-bench/src/data_structures.rs b/jets-bench/src/data_structures.rs index edafeba8..a9fd5ded 100644 --- a/jets-bench/src/data_structures.rs +++ b/jets-bench/src/data_structures.rs @@ -63,7 +63,7 @@ pub fn var_len_buf_from_slice(v: &[u8], mut n: usize) -> Result { while n > 0 { let ty = Final::two_two_n(n); let v = if v.len() >= (1 << (n + 1)) { - let val = iter.read_value(&ty)?; + let val = Value::from_compact_bits(&mut iter, &ty)?; Value::some(val) } else { Value::none(ty) diff --git a/src/bit_encoding/bititer.rs b/src/bit_encoding/bititer.rs index c7e8d811..0c2fad86 100644 --- a/src/bit_encoding/bititer.rs +++ b/src/bit_encoding/bititer.rs @@ -9,10 +9,8 @@ //! `Iterator`. //! -use crate::types::Final; -use crate::{decode, types}; -use crate::{Cmr, FailEntropy, Value}; -use std::sync::Arc; +use crate::decode; +use crate::{Cmr, FailEntropy}; use std::{error, fmt}; /// Attempted to read from a bit iterator, but there was no more data @@ -221,55 +219,6 @@ impl> BitIter { Ok(FailEntropy::from_byte_array(ret)) } - /// Decode a value from bits, based on the given type. - pub fn read_value(&mut self, ty: &Final) -> Result { - enum State<'a> { - ProcessType(&'a Final), - DoSumL(Arc), - DoSumR(Arc), - DoProduct, - } - - let mut stack = vec![State::ProcessType(ty)]; - let mut result_stack = vec![]; - while let Some(state) = stack.pop() { - match state { - State::ProcessType(ty) => match ty.bound() { - types::CompleteBound::Unit => result_stack.push(Value::unit()), - types::CompleteBound::Sum(ref l, ref r) => { - if self.read_bit()? { - stack.push(State::DoSumR(Arc::clone(l))); - stack.push(State::ProcessType(r)); - } else { - stack.push(State::DoSumL(Arc::clone(r))); - stack.push(State::ProcessType(l)); - } - } - types::CompleteBound::Product(ref l, ref r) => { - stack.push(State::DoProduct); - stack.push(State::ProcessType(r)); - stack.push(State::ProcessType(l)); - } - }, - State::DoSumL(r) => { - let val = result_stack.pop().unwrap(); - result_stack.push(Value::left(val, r)); - } - State::DoSumR(l) => { - let val = result_stack.pop().unwrap(); - result_stack.push(Value::right(l, val)); - } - State::DoProduct => { - let val_r = result_stack.pop().unwrap(); - let val_l = result_stack.pop().unwrap(); - result_stack.push(Value::product(val_l, val_r)); - } - } - } - debug_assert_eq!(result_stack.len(), 1); - Ok(result_stack.pop().unwrap()) - } - /// Decode a natural number from bits. /// /// If a bound is specified, then the decoding terminates before trying to diff --git a/src/bit_machine/mod.rs b/src/bit_machine/mod.rs index 8b56873c..bfb98c51 100644 --- a/src/bit_machine/mod.rs +++ b/src/bit_machine/mod.rs @@ -358,10 +358,11 @@ impl BitMachine { if output_width > 0 { let out_frame = self.write.last_mut().unwrap(); out_frame.reset_cursor(); - let value = out_frame - .as_bit_iter(&self.data) - .read_value(&program.arrow().target) - .expect("Decode value of output frame"); + let value = Value::from_padded_bits( + &mut out_frame.as_bit_iter(&self.data), + &program.arrow().target, + ) + .expect("Decode value of output frame"); Ok(value) } else { diff --git a/src/human_encoding/parse/ast.rs b/src/human_encoding/parse/ast.rs index d34153e2..aa2214af 100644 --- a/src/human_encoding/parse/ast.rs +++ b/src/human_encoding/parse/ast.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use crate::human_encoding::{Error, ErrorSet, Position, WitnessOrHole}; use crate::jet::Jet; -use crate::{node, types}; +use crate::{node, types, Value}; use crate::{BitIter, Cmr, FailEntropy}; use santiago::grammar::{Associativity, Grammar}; use santiago::lexer::{Lexeme, LexerRules}; @@ -647,7 +647,7 @@ fn grammar() -> Grammar> { let ty = types::Final::two_two_n(bit_length.trailing_zeros() as usize); // unwrap ok here since literally every sequence of bits is a valid // value for the given type - let value = iter.read_value(&ty).unwrap(); + let value = Value::from_compact_bits(&mut iter, &ty).unwrap(); Ast::Expression(Expression { inner: ExprInner::Inline(node::Inner::Word(value)), position, diff --git a/src/node/redeem.rs b/src/node/redeem.rs index 30880419..de7e5445 100644 --- a/src/node/redeem.rs +++ b/src/node/redeem.rs @@ -299,7 +299,7 @@ impl RedeemNode { ) -> Result { let arrow = data.node.data.arrow(); let target_ty = arrow.target.finalize()?; - self.bits.read_value(&target_ty).map_err(Error::from) + Value::from_compact_bits(self.bits, &target_ty).map_err(Error::from) } fn convert_disconnect( diff --git a/src/value.rs b/src/value.rs index c9080e37..f982b317 100644 --- a/src/value.rs +++ b/src/value.rs @@ -8,6 +8,7 @@ use crate::dag::{Dag, DagLike, NoSharing}; use crate::types::Final; +use crate::{types, EarlyEndOfStreamError}; use std::collections::VecDeque; use std::fmt; use std::hash::Hash; @@ -388,6 +389,138 @@ impl<'a> Iterator for PaddedBitsIter<'a> { } } +trait Padding { + fn read_left_padding>( + bits: &mut I, + ty_l: &Final, + ty_r: &Final, + ) -> Result<(), EarlyEndOfStreamError>; + + fn read_right_padding>( + bits: &mut I, + ty_l: &Final, + ty_r: &Final, + ) -> Result<(), EarlyEndOfStreamError>; +} + +enum CompactEncoding {} +enum PaddedEncoding {} + +impl Padding for CompactEncoding { + fn read_left_padding>( + _: &mut I, + _: &Final, + _: &Final, + ) -> Result<(), EarlyEndOfStreamError> { + // no padding + Ok(()) + } + + fn read_right_padding>( + _: &mut I, + _: &Final, + _: &Final, + ) -> Result<(), EarlyEndOfStreamError> { + // no padding + Ok(()) + } +} + +impl Padding for PaddedEncoding { + fn read_left_padding>( + bits: &mut I, + ty_l: &Final, + ty_r: &Final, + ) -> Result<(), EarlyEndOfStreamError> { + for _ in 0..ty_l.pad_left(ty_r) { + let _padding = bits.next().ok_or(EarlyEndOfStreamError)?; + } + Ok(()) + } + + fn read_right_padding>( + bits: &mut I, + ty_l: &Final, + ty_r: &Final, + ) -> Result<(), EarlyEndOfStreamError> { + for _ in 0..ty_l.pad_left(ty_r) { + let _padding = bits.next().ok_or(EarlyEndOfStreamError)?; + } + Ok(()) + } +} + +impl Value { + fn from_bits, P: Padding>( + bits: &mut I, + ty: &Final, + ) -> Result { + enum State<'a> { + ProcessType(&'a Final), + DoSumL(Arc), + DoSumR(Arc), + DoProduct, + } + + let mut stack = vec![State::ProcessType(ty)]; + let mut result_stack = vec![]; + while let Some(state) = stack.pop() { + match state { + State::ProcessType(ty) => match ty.bound() { + types::CompleteBound::Unit => result_stack.push(Value::unit()), + types::CompleteBound::Sum(ref l, ref r) => { + if !bits.next().ok_or(EarlyEndOfStreamError)? { + P::read_left_padding(bits, l, r)?; + stack.push(State::DoSumL(Arc::clone(r))); + stack.push(State::ProcessType(l)); + } else { + P::read_right_padding(bits, l, r)?; + stack.push(State::DoSumR(Arc::clone(l))); + stack.push(State::ProcessType(r)); + } + } + types::CompleteBound::Product(ref l, ref r) => { + stack.push(State::DoProduct); + stack.push(State::ProcessType(r)); + stack.push(State::ProcessType(l)); + } + }, + State::DoSumL(r) => { + let val = result_stack.pop().unwrap(); + result_stack.push(Value::left(val, r)); + } + State::DoSumR(l) => { + let val = result_stack.pop().unwrap(); + result_stack.push(Value::right(l, val)); + } + State::DoProduct => { + let val_r = result_stack.pop().unwrap(); + let val_l = result_stack.pop().unwrap(); + result_stack.push(Value::product(val_l, val_r)); + } + } + } + debug_assert_eq!(result_stack.len(), 1); + Ok(result_stack.pop().unwrap()) + } + + /// Decode a value of the given type from its compact bit encoding. + pub fn from_compact_bits>( + bits: &mut I, + ty: &Final, + ) -> Result { + Self::from_bits::<_, CompactEncoding>(bits, ty) + } + + /// Decode a value of the given type from its padded bit encoding. + pub fn from_padded_bits>( + bits: &mut I, + ty: &Final, + ) -> Result { + Self::from_bits::<_, PaddedEncoding>(bits, ty) + } +} + #[cfg(test)] mod tests { use super::*;