essential_vm/
sets.rs

1use crate::error::{DecodeError, OpResult, StackError};
2use essential_types::Word;
3
4#[cfg(test)]
5mod tests;
6
7#[cfg(test)]
8/// Encode a set into the stack.
9pub(crate) fn encode_set<S, I>(set: S, stack: &mut crate::Stack) -> OpResult<()>
10where
11    I: ExactSizeIterator<Item = Word>,
12    S: ExactSizeIterator<Item = I>,
13{
14    let mut len = set.len();
15    for item in set {
16        let item_len = item.len();
17        len = len
18            .checked_add(item_len)
19            .ok_or(crate::error::EncodeError::ItemLengthTooLarge(len))?;
20        stack.extend(item)?;
21        stack.push(
22            item_len
23                .try_into()
24                .map_err(|_| crate::error::EncodeError::ItemLengthTooLarge(item_len))?,
25        )?;
26    }
27    stack.push(
28        len.try_into()
29            .map_err(|_| crate::error::EncodeError::ItemLengthTooLarge(len))?,
30    )?;
31    Ok(())
32}
33
34/// Decode a set, starting from the top of slice.
35pub(crate) fn decode_set(words: &[Word]) -> impl '_ + Iterator<Item = OpResult<&[Word]>> {
36    let mut ws = words;
37    std::iter::from_fn(move || {
38        let (len, rest) = ws.split_last()?;
39        let ix = match usize::try_from(*len)
40            .map_err(|_| StackError::Overflow.into())
41            .and_then(|len| {
42                rest.len()
43                    .checked_sub(len)
44                    .ok_or_else(|| DecodeError::Set(words.to_vec()).into())
45            }) {
46            Ok(ix) => ix,
47            Err(e) => return Some(Err(e)),
48        };
49        let (rest, key) = rest.split_at(ix);
50        ws = rest;
51        Some(Ok(key))
52    })
53}