Skip to content

Commit 7c37dbf

Browse files
committed
feat: Add ValueDecoder trait
ValueDecoder allows all Boolean iterators to decode Simplicity values. This is necessary for alternative implementations of the Bit Machine, such as on the web IDE. We can extend the trait to cover natural numbers, CMRs and so on in the future. This commit is limited to decoding values, which is what I need.
1 parent 24367c8 commit 7c37dbf

File tree

7 files changed

+56
-47
lines changed

7 files changed

+56
-47
lines changed

jets-bench/src/data_structures.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use simplicity::{
99
hashes::Hash,
1010
hex::FromHex,
1111
types::Final,
12-
BitIter, Error, Value,
12+
BitIter, Error, Value, ValueDecoder,
1313
};
1414

1515
/// Engine to compute SHA256 hash function.
@@ -63,7 +63,7 @@ pub fn var_len_buf_from_slice(v: &[u8], mut n: usize) -> Result<Value, Error> {
6363
while n > 0 {
6464
let ty = Final::two_two_n(n);
6565
let v = if v.len() >= (1 << (n + 1)) {
66-
let val = iter.read_value(&ty)?;
66+
let val = iter.decode_value(&ty)?;
6767
Value::some(val)
6868
} else {
6969
Value::none(ty)

src/bit_encoding/bititer.rs

+46-37
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,52 @@ impl<I: Iterator<Item = u8>> BitIter<I> {
221221
Ok(FailEntropy::from_byte_array(ret))
222222
}
223223

224+
/// Decode a natural number from bits.
225+
///
226+
/// If a bound is specified, then the decoding terminates before trying to
227+
/// decode a larger number.
228+
pub fn read_natural(&mut self, bound: Option<usize>) -> Result<usize, decode::Error> {
229+
decode::decode_natural(self, bound)
230+
}
231+
232+
/// Accessor for the number of bits which have been read,
233+
/// in total, from this iterator
234+
pub fn n_total_read(&self) -> usize {
235+
self.total_read
236+
}
237+
238+
/// Consumes the bit iterator, checking that there are no remaining
239+
/// bytes and that any unread bits are zero.
240+
pub fn close(mut self) -> Result<(), CloseError> {
241+
if let Some(first_byte) = self.iter.next() {
242+
return Err(CloseError::TrailingBytes { first_byte });
243+
}
244+
245+
debug_assert!(self.read_bits >= 1);
246+
debug_assert!(self.read_bits <= 8);
247+
let n_bits = 8 - self.read_bits;
248+
let masked_padding = self.cached_byte & ((1u8 << n_bits) - 1);
249+
if masked_padding != 0 {
250+
Err(CloseError::IllegalPadding {
251+
masked_padding,
252+
n_bits,
253+
})
254+
} else {
255+
Ok(())
256+
}
257+
}
258+
}
259+
260+
/// Functionality for Boolean iterators to decode Simplicity values.
261+
pub trait ValueDecoder {
224262
/// Decode a value from bits, based on the given type.
225-
pub fn read_value(&mut self, ty: &Final) -> Result<Value, EarlyEndOfStreamError> {
263+
///
264+
/// Return `None` if there are not enough bits.
265+
fn decode_value(&mut self, ty: &Final) -> Result<Value, EarlyEndOfStreamError>;
266+
}
267+
268+
impl<I: Iterator<Item = bool>> ValueDecoder for I {
269+
fn decode_value(&mut self, ty: &Final) -> Result<Value, EarlyEndOfStreamError> {
226270
enum State<'a> {
227271
ProcessType(&'a Final),
228272
DoSumL(Arc<Final>),
@@ -237,7 +281,7 @@ impl<I: Iterator<Item = u8>> BitIter<I> {
237281
State::ProcessType(ty) => match ty.bound() {
238282
types::CompleteBound::Unit => result_stack.push(Value::unit()),
239283
types::CompleteBound::Sum(ref l, ref r) => {
240-
if self.read_bit()? {
284+
if self.next().ok_or(EarlyEndOfStreamError)? {
241285
stack.push(State::DoSumR(Arc::clone(l)));
242286
stack.push(State::ProcessType(r));
243287
} else {
@@ -269,41 +313,6 @@ impl<I: Iterator<Item = u8>> BitIter<I> {
269313
debug_assert_eq!(result_stack.len(), 1);
270314
Ok(result_stack.pop().unwrap())
271315
}
272-
273-
/// Decode a natural number from bits.
274-
///
275-
/// If a bound is specified, then the decoding terminates before trying to
276-
/// decode a larger number.
277-
pub fn read_natural(&mut self, bound: Option<usize>) -> Result<usize, decode::Error> {
278-
decode::decode_natural(self, bound)
279-
}
280-
281-
/// Accessor for the number of bits which have been read,
282-
/// in total, from this iterator
283-
pub fn n_total_read(&self) -> usize {
284-
self.total_read
285-
}
286-
287-
/// Consumes the bit iterator, checking that there are no remaining
288-
/// bytes and that any unread bits are zero.
289-
pub fn close(mut self) -> Result<(), CloseError> {
290-
if let Some(first_byte) = self.iter.next() {
291-
return Err(CloseError::TrailingBytes { first_byte });
292-
}
293-
294-
debug_assert!(self.read_bits >= 1);
295-
debug_assert!(self.read_bits <= 8);
296-
let n_bits = 8 - self.read_bits;
297-
let masked_padding = self.cached_byte & ((1u8 << n_bits) - 1);
298-
if masked_padding != 0 {
299-
Err(CloseError::IllegalPadding {
300-
masked_padding,
301-
n_bits,
302-
})
303-
} else {
304-
Ok(())
305-
}
306-
}
307316
}
308317

309318
/// Functionality for Boolean iterators to collect their bits or bytes.

src/bit_encoding/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ mod bitwriter;
1313
pub mod decode;
1414
pub mod encode;
1515

16-
pub use bititer::{u2, BitCollector, BitIter, CloseError, EarlyEndOfStreamError};
16+
pub use bititer::{u2, BitCollector, BitIter, CloseError, EarlyEndOfStreamError, ValueDecoder};
1717
pub use bitwriter::{write_to_vec, BitWriter};

src/bit_machine/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use std::error;
1212
use std::fmt;
1313
use std::sync::Arc;
1414

15-
use crate::analysis;
1615
use crate::jet::{Jet, JetFailed};
1716
use crate::node::{self, RedeemNode};
1817
use crate::types::Final;
18+
use crate::{analysis, ValueDecoder};
1919
use crate::{Cmr, FailEntropy, Value};
2020
use frame::Frame;
2121

@@ -360,7 +360,7 @@ impl BitMachine {
360360
out_frame.reset_cursor();
361361
let value = out_frame
362362
.as_bit_iter(&self.data)
363-
.read_value(&program.arrow().target)
363+
.decode_value(&program.arrow().target)
364364
.expect("Decode value of output frame");
365365

366366
Ok(value)

src/human_encoding/parse/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::sync::Arc;
77

88
use crate::human_encoding::{Error, ErrorSet, Position, WitnessOrHole};
99
use crate::jet::Jet;
10-
use crate::{node, types};
10+
use crate::{node, types, ValueDecoder};
1111
use crate::{BitIter, Cmr, FailEntropy};
1212
use santiago::grammar::{Associativity, Grammar};
1313
use santiago::lexer::{Lexeme, LexerRules};
@@ -647,7 +647,7 @@ fn grammar<J: Jet + 'static>() -> Grammar<Ast<J>> {
647647
let ty = types::Final::two_two_n(bit_length.trailing_zeros() as usize);
648648
// unwrap ok here since literally every sequence of bits is a valid
649649
// value for the given type
650-
let value = iter.read_value(&ty).unwrap();
650+
let value = iter.decode_value(&ty).unwrap();
651651
Ast::Expression(Expression {
652652
inner: ExprInner::Inline(node::Inner::Word(value)),
653653
position,

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ mod value;
4242
pub use bit_encoding::decode;
4343
pub use bit_encoding::encode;
4444
pub use bit_encoding::{
45-
u2, BitCollector, BitIter, CloseError as BitIterCloseError, EarlyEndOfStreamError,
45+
u2, BitCollector, BitIter, CloseError as BitIterCloseError, EarlyEndOfStreamError, ValueDecoder,
4646
};
4747
pub use bit_encoding::{write_to_vec, BitWriter};
4848

src/node/redeem.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::analysis::NodeBounds;
44
use crate::dag::{DagLike, InternalSharing, MaxSharing, PostOrderIterItem};
55
use crate::jet::Jet;
66
use crate::types::{self, arrow::FinalArrow};
7-
use crate::{encode, WitnessNode};
7+
use crate::{encode, ValueDecoder, WitnessNode};
88
use crate::{Amr, BitIter, BitWriter, Cmr, Error, FirstPassImr, Imr, Value};
99

1010
use super::{
@@ -299,7 +299,7 @@ impl<J: Jet> RedeemNode<J> {
299299
) -> Result<Value, Self::Error> {
300300
let arrow = data.node.data.arrow();
301301
let target_ty = arrow.target.finalize()?;
302-
self.bits.read_value(&target_ty).map_err(Error::from)
302+
self.bits.decode_value(&target_ty).map_err(Error::from)
303303
}
304304

305305
fn convert_disconnect(

0 commit comments

Comments
 (0)