Skip to content

Commit

Permalink
feat: Decode value from compact / padded encoding
Browse files Browse the repository at this point in the history
Decode a Simplicity value as an associated method of the Value struct.
Differentiate between compact and padded encoding.
  • Loading branch information
uncomputable committed Sep 27, 2024
1 parent 70aefd1 commit 9ef06ef
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 61 deletions.
2 changes: 1 addition & 1 deletion jets-bench/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn var_len_buf_from_slice(v: &[u8], mut n: usize) -> Result<Value, Error> {
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)
Expand Down
55 changes: 2 additions & 53 deletions src/bit_encoding/bititer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
//! `Iterator<Item=bool>`.
//!
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
Expand Down Expand Up @@ -221,55 +219,6 @@ impl<I: Iterator<Item = u8>> BitIter<I> {
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<Value, EarlyEndOfStreamError> {
enum State<'a> {
ProcessType(&'a Final),
DoSumL(Arc<Final>),
DoSumR(Arc<Final>),
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
Expand Down
9 changes: 5 additions & 4 deletions src/bit_machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/human_encoding/parse/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -647,7 +647,7 @@ fn grammar<J: Jet + 'static>() -> Grammar<Ast<J>> {
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,
Expand Down
2 changes: 1 addition & 1 deletion src/node/redeem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl<J: Jet> RedeemNode<J> {
) -> Result<Value, Self::Error> {
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(
Expand Down
133 changes: 133 additions & 0 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -388,6 +389,138 @@ impl<'a> Iterator for PaddedBitsIter<'a> {
}
}

trait Padding {
fn read_left_padding<I: Iterator<Item = bool>>(
bits: &mut I,
ty_l: &Final,
ty_r: &Final,
) -> Result<(), EarlyEndOfStreamError>;

fn read_right_padding<I: Iterator<Item = bool>>(
bits: &mut I,
ty_l: &Final,
ty_r: &Final,
) -> Result<(), EarlyEndOfStreamError>;
}

enum CompactEncoding {}
enum PaddedEncoding {}

impl Padding for CompactEncoding {
fn read_left_padding<I: Iterator<Item = bool>>(
_: &mut I,
_: &Final,
_: &Final,
) -> Result<(), EarlyEndOfStreamError> {
// no padding
Ok(())
}

fn read_right_padding<I: Iterator<Item = bool>>(
_: &mut I,
_: &Final,
_: &Final,
) -> Result<(), EarlyEndOfStreamError> {
// no padding
Ok(())
}
}

impl Padding for PaddedEncoding {
fn read_left_padding<I: Iterator<Item = bool>>(
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<I: Iterator<Item = bool>>(
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<I: Iterator<Item = bool>, P: Padding>(
bits: &mut I,
ty: &Final,
) -> Result<Self, EarlyEndOfStreamError> {
enum State<'a> {
ProcessType(&'a Final),
DoSumL(Arc<Final>),
DoSumR(Arc<Final>),
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<I: Iterator<Item = bool>>(
bits: &mut I,
ty: &Final,
) -> Result<Self, EarlyEndOfStreamError> {
Self::from_bits::<_, CompactEncoding>(bits, ty)
}

/// Decode a value of the given type from its padded bit encoding.
pub fn from_padded_bits<I: Iterator<Item = bool>>(
bits: &mut I,
ty: &Final,
) -> Result<Self, EarlyEndOfStreamError> {
Self::from_bits::<_, PaddedEncoding>(bits, ty)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit 9ef06ef

Please sign in to comment.