use std::{cell::RefCell, fmt, rc::Rc};
use crate::{TypeSet, TypedValue, value::LoadStore};
type BoxedIter<T> = std::iter::Peekable<Box<dyn Iterator<Item = TypedValue<T>>>>;
pub struct SomniIterator<T: TypeSet> {
inner: Rc<RefCell<BoxedIter<T>>>,
}
impl<T: TypeSet> SomniIterator<T> {
pub fn new<I>(iter: I) -> Self
where
I: IntoIterator<Item = TypedValue<T>> + 'static,
{
let boxed: Box<dyn Iterator<Item = TypedValue<T>>> = Box::new(iter.into_iter());
Self {
inner: Rc::new(RefCell::new(boxed.peekable())),
}
}
#[doc(hidden)]
pub fn has_next(&self) -> bool {
self.inner.borrow_mut().peek().is_some()
}
#[doc(hidden)]
pub fn next_value(&self) -> Option<TypedValue<T>> {
self.inner.borrow_mut().next()
}
}
impl<T: TypeSet> Clone for SomniIterator<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T: TypeSet> fmt::Debug for SomniIterator<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<iter>")
}
}
impl<T: TypeSet> PartialEq for SomniIterator<T> {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.inner, &other.inner)
}
}
impl<T> LoadStore<WithIterator<T>> for SomniIterator<T>
where
T: TypeSet,
WithIterator<T>: TypeSet<Iterator = SomniIterator<T>>,
{
type Output<'s> = Self;
fn load<'s>(
_ctx: &'s WithIterator<T>,
typed: &'s TypedValue<WithIterator<T>>,
) -> Option<Self::Output<'s>> {
if let TypedValue::Iter(iter) = typed {
Some(iter.clone())
} else {
None
}
}
fn store(&self, _ctx: &mut WithIterator<T>) -> TypedValue<WithIterator<T>> {
TypedValue::Iter(self.clone())
}
}
pub struct WithIterator<T: TypeSet> {
pub inner: T,
}
impl<T: TypeSet> Default for WithIterator<T> {
fn default() -> Self {
Self {
inner: T::default(),
}
}
}
impl<T: TypeSet> fmt::Debug for WithIterator<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WithIterator")
.field("inner", &self.inner)
.finish()
}
}
#[macro_export]
macro_rules! impl_with_iterator {
($inner:ty) => {
impl $crate::TypeSet for $crate::WithIterator<$inner> {
type Parser = <$inner as $crate::TypeSet>::Parser;
type Integer = <$inner as $crate::TypeSet>::Integer;
type SignedInteger = <$inner as $crate::TypeSet>::SignedInteger;
type Float = <$inner as $crate::TypeSet>::Float;
type String = <$inner as $crate::TypeSet>::String;
type Iterator = $crate::SomniIterator<$inner>;
fn to_signed(v: Self::Integer) -> Result<Self::SignedInteger, $crate::OperatorError> {
<$inner as $crate::TypeSet>::to_signed(v)
}
fn to_usize(v: Self::Integer) -> Result<usize, $crate::OperatorError> {
<$inner as $crate::TypeSet>::to_usize(v)
}
fn int_from_usize(v: usize) -> Self::Integer {
<$inner as $crate::TypeSet>::int_from_usize(v)
}
fn load_string<'s>(&'s self, str: &'s Self::String) -> &'s str {
self.inner.load_string(str)
}
fn store_string(&mut self, str: &str) -> Self::String {
self.inner.store_string(str)
}
fn iter_has_next(&self, iter: &Self::Iterator) -> bool {
iter.has_next()
}
fn iter_next(&self, iter: &Self::Iterator) -> Option<$crate::TypedValue<Self>> {
fn convert(
value: $crate::TypedValue<$inner>,
) -> $crate::TypedValue<$crate::WithIterator<$inner>> {
use $crate::TypedValue;
match value {
TypedValue::Void => TypedValue::Void,
TypedValue::MaybeSignedInt(v) => TypedValue::MaybeSignedInt(v),
TypedValue::Int(v) => TypedValue::Int(v),
TypedValue::SignedInt(v) => TypedValue::SignedInt(v),
TypedValue::Float(v) => TypedValue::Float(v),
TypedValue::Bool(v) => TypedValue::Bool(v),
TypedValue::String(v) => TypedValue::String(v),
TypedValue::Iter(never) => match never {},
TypedValue::Struct(s) => {
let (name, fields) = s.into_parts();
TypedValue::Struct($crate::SomniStruct::new(
name,
fields.into_iter().map(|(k, v)| (k, convert(v))).collect(),
))
}
TypedValue::Ref(r) => TypedValue::Ref(r),
}
}
iter.next_value().map(convert)
}
}
};
}
impl_with_iterator!(crate::DefaultTypeSet);
impl_with_iterator!(crate::TypeSet32);
impl_with_iterator!(crate::TypeSet128);