Skip to main content

somni_expr/
iter.rs

1//! Iterator support for type sets.
2//!
3//! Iterators are opaque values ([`TypedValue::Iter`]). The concrete iterator object
4//! is carried directly by the value.
5//!
6//! The default type sets do not support iteration (their [`TypeSet::Iterator`] is the
7//! uninhabited [`NoIterator`](crate::NoIterator)). [`WithIterator`] wraps any
8//! [`TypeSet`] and swaps in a real, reference-counted iterator ([`SomniIterator`]),
9//! enabling `for` loops (and any host function that produces a [`SomniIterator`]) for
10//! the wrapped type set.
11
12use std::{cell::RefCell, fmt, rc::Rc};
13
14use crate::{value::LoadStore, TypeSet, TypedValue};
15
16/// A boxed, peekable iterator yielding values of the *inner* type set.
17///
18/// The inner type set `T` and its [`WithIterator`] wrapper share all of their
19/// scalar associated types, so values convert between the two for free.
20type BoxedIter<T> = std::iter::Peekable<Box<dyn Iterator<Item = TypedValue<T>>>>;
21
22/// A live iterator value, backed by a reference-counted Rust iterator.
23///
24/// This is the [`TypeSet::Iterator`] type used by [`WithIterator`]: a
25/// [`TypedValue::Iter`] carries one of these directly (cloning shares the same
26/// underlying iterator). Return one from a function registered on a
27/// [`Context`](crate::Context) that uses a [`WithIterator`] type set to make it
28/// iterable with a `for` loop.
29pub struct SomniIterator<T: TypeSet> {
30    inner: Rc<RefCell<BoxedIter<T>>>,
31}
32
33impl<T: TypeSet> SomniIterator<T> {
34    /// Creates an iterator from anything that yields Somni values.
35    pub fn new<I>(iter: I) -> Self
36    where
37        I: IntoIterator<Item = TypedValue<T>> + 'static,
38    {
39        let boxed: Box<dyn Iterator<Item = TypedValue<T>>> = Box::new(iter.into_iter());
40        Self {
41            inner: Rc::new(RefCell::new(boxed.peekable())),
42        }
43    }
44
45    /// Returns whether the iterator can yield another value.
46    #[doc(hidden)]
47    pub fn has_next(&self) -> bool {
48        self.inner.borrow_mut().peek().is_some()
49    }
50
51    /// Advances the iterator, returning its next value (in the inner type set).
52    #[doc(hidden)]
53    pub fn next_value(&self) -> Option<TypedValue<T>> {
54        self.inner.borrow_mut().next()
55    }
56}
57
58impl<T: TypeSet> Clone for SomniIterator<T> {
59    fn clone(&self) -> Self {
60        Self {
61            inner: self.inner.clone(),
62        }
63    }
64}
65
66impl<T: TypeSet> fmt::Debug for SomniIterator<T> {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_str("<iter>")
69    }
70}
71
72impl<T: TypeSet> PartialEq for SomniIterator<T> {
73    fn eq(&self, other: &Self) -> bool {
74        Rc::ptr_eq(&self.inner, &other.inner)
75    }
76}
77
78impl<T> LoadStore<WithIterator<T>> for SomniIterator<T>
79where
80    T: TypeSet,
81    WithIterator<T>: TypeSet<Iterator = SomniIterator<T>>,
82{
83    type Output<'s> = Self;
84
85    fn load<'s>(
86        _ctx: &'s WithIterator<T>,
87        typed: &'s TypedValue<WithIterator<T>>,
88    ) -> Option<Self::Output<'s>> {
89        if let TypedValue::Iter(iter) = typed {
90            Some(iter.clone())
91        } else {
92            None
93        }
94    }
95
96    fn store(&self, _ctx: &mut WithIterator<T>) -> TypedValue<WithIterator<T>> {
97        TypedValue::Iter(self.clone())
98    }
99}
100
101/// A [`TypeSet`] wrapper that adds iterator support to the wrapped type set `T`.
102///
103/// All scalar behavior is delegated to `T`; this only replaces the inert
104/// [`NoIterator`](crate::NoIterator) with a real [`SomniIterator`] and implements the
105/// [`iter_has_next`](TypeSet::iter_has_next) / [`iter_next`](TypeSet::iter_next)
106/// protocol.
107pub struct WithIterator<T: TypeSet> {
108    /// The inner type set.
109    pub inner: T,
110}
111
112impl<T: TypeSet> Default for WithIterator<T> {
113    fn default() -> Self {
114        Self {
115            inner: T::default(),
116        }
117    }
118}
119
120impl<T: TypeSet> fmt::Debug for WithIterator<T> {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.debug_struct("WithIterator")
123            .field("inner", &self.inner)
124            .finish()
125    }
126}
127
128/// Implements [`TypeSet`] for `WithIterator<$inner>` by delegating scalar behavior to
129/// the concrete inner type set and swapping in a real iterator type.
130///
131/// A generic `impl<T: TypeSet> TypeSet for WithIterator<T>` is not possible: the
132/// trait's `Integer: LoadStore<Self>` bounds can only be discharged for a concrete
133/// inner type set (otherwise the trait solver cycles through the blanket `LoadStore`
134/// impls). Invoke this macro to enable iterators for a custom type set whose iterator
135/// type is [`NoIterator`](crate::NoIterator).
136#[macro_export]
137macro_rules! impl_with_iterator {
138    ($inner:ty) => {
139        impl $crate::TypeSet for $crate::WithIterator<$inner> {
140            type Parser = <$inner as $crate::TypeSet>::Parser;
141            type Integer = <$inner as $crate::TypeSet>::Integer;
142            type SignedInteger = <$inner as $crate::TypeSet>::SignedInteger;
143            type Float = <$inner as $crate::TypeSet>::Float;
144            type String = <$inner as $crate::TypeSet>::String;
145            type Iterator = $crate::SomniIterator<$inner>;
146
147            fn to_signed(v: Self::Integer) -> Result<Self::SignedInteger, $crate::OperatorError> {
148                <$inner as $crate::TypeSet>::to_signed(v)
149            }
150
151            fn to_usize(v: Self::Integer) -> Result<usize, $crate::OperatorError> {
152                <$inner as $crate::TypeSet>::to_usize(v)
153            }
154
155            fn int_from_usize(v: usize) -> Self::Integer {
156                <$inner as $crate::TypeSet>::int_from_usize(v)
157            }
158
159            fn load_string<'s>(&'s self, str: &'s Self::String) -> &'s str {
160                self.inner.load_string(str)
161            }
162
163            fn store_string(&mut self, str: &str) -> Self::String {
164                self.inner.store_string(str)
165            }
166
167            fn iter_has_next(&self, iter: &Self::Iterator) -> bool {
168                iter.has_next()
169            }
170
171            fn iter_next(&self, iter: &Self::Iterator) -> Option<$crate::TypedValue<Self>> {
172                iter.next_value().map(|value| match value {
173                    TypedValue::Void => TypedValue::Void,
174                    TypedValue::MaybeSignedInt(v) => TypedValue::MaybeSignedInt(v),
175                    TypedValue::Int(v) => TypedValue::Int(v),
176                    TypedValue::SignedInt(v) => TypedValue::SignedInt(v),
177                    TypedValue::Float(v) => TypedValue::Float(v),
178                    TypedValue::Bool(v) => TypedValue::Bool(v),
179                    TypedValue::String(v) => TypedValue::String(v),
180                    TypedValue::Iter(never) => match never {},
181                })
182            }
183        }
184    };
185}
186
187impl_with_iterator!(crate::DefaultTypeSet);
188impl_with_iterator!(crate::TypeSet32);
189impl_with_iterator!(crate::TypeSet128);