//! Basic implementation of a stack/linked list. use crate::core::*; use crate::std::inlining::*; use crate::std::nullable::*; use crate::std::point::*; use crate::std::*; /// Node containing a (nullable) reference to the next node and an element. pub struct StackNode<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { /// Reference comes first due to being inlineable. pub rest: Stack<'a, Ctx, A>, /// Unlike the original implementation in Python, doesn't default to using Point. pub element: Rc, } /// Type representing a stack, an alias to a [Nullable] of a [StackNode]. pub type Stack<'a, Ctx, A> = Nullable<'a, Ctx, StackNode<'a, Ctx, A>>; pub struct StackNodeFactory<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { element_factory: A::Fctr, } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> StackNodeFactory<'a, Ctx, A> { fn new(factory: A::Fctr) -> Self { StackNodeFactory { element_factory: factory, } } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for StackNode<'a, Ctx, A> { fn serialize(&self, serializer: &mut dyn Serializer) { self.rest.serialize(serializer); self.element.serialize(serializer); } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for StackNode<'a, Ctx, A> { type Fctr = StackNodeFactory<'a, Ctx, A>; fn factory(&self) -> Self::Fctr { StackNodeFactory::new(self.element.factory()) } fn points(&self, points: &mut Vec>>) { self.rest.points(points); self.element.points(points); } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for StackNodeFactory<'a, Ctx, A> { fn clone(&self) -> Self { StackNodeFactory::new(self.element_factory.clone()) } } #[derive(Debug)] pub enum StackParseError { Point(PointParseError), Element(ElementParseError), } impl Display for StackParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { StackParseError::Point(ppe) => { f.write_fmt(format_args!("can't parse stack's next pointer: {}", ppe)) } StackParseError::Element(epe) => { f.write_fmt(format_args!("can't parse stack's element: {}", epe)) } } } } impl Error for StackParseError {} impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> for StackNodeFactory<'a, Ctx, A> { type Mtbl = StackNode<'a, Ctx, A>; type ParseError = StackParseError<>::ParseError>; fn deserialize( &self, deserializer: &mut dyn Deserializer, resolver: Rc>, addresses: &mut Addresses, ) -> ParseResult<'a, Ctx, Self> { let rest = match NullableFactory::new(self.clone()).deserialize( deserializer, resolver.clone(), addresses, ) { Ok(rest) => rest, Err(ppe) => { return Err(StackParseError::Point(ppe)); } }; let element = Rc::new( match self .element_factory .deserialize(deserializer, resolver, addresses) { Ok(element) => element, Err(epe) => { return Err(StackParseError::Element(epe)); } }, ); Ok(StackNode { rest, element }) } fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { StackParseError::Element(self.element_factory.unexpected_tail(tail)) } } /// See [`StackVecResult`]. pub type StackFaiure<'a, Ctx, A> = ResolutionFailure<'a, Ctx, StackNode<'a, Ctx, A>>; /// See [`StackVecWrapped`]. pub type StackVecResult<'a, Ctx, A> = Result>, StackFaiure<'a, Ctx, A>>; /// See [`ExtStack::vec`]. pub type StackVecWrapped<'a, Ctx, A> = Wrapped<'a, Ctx, StackVecResult<'a, Ctx, A>>; /// Extention trait with helper methods for [Stack]s. pub trait ExtStack<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>: Mentionable<'a, Ctx> { /// Get an empty stack ([`Nullable::Null`]). fn empty(factory: A::Fctr) -> Self; /// Get the corresponding factory. fn f(factory: A::Fctr) -> Self::Fctr; /// Add one element. /// /// Note: consumes the stack. For non-consuming version do `.clone()` before adding. fn add(self, element: A) -> Self; /// Collect all the elements into a [`Vec`]. fn vec(self) -> StackVecWrapped<'a, Ctx, A>; } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for Stack<'a, Ctx, A> { fn empty(factory: A::Fctr) -> Self { Nullable::Null(StackNodeFactory::new(factory.clone())) } fn f(factory: A::Fctr) -> Self::Fctr { NullableFactory::new(StackNodeFactory::new(factory.clone())) } fn add(self, element: A) -> Self { Nullable::NotNull( StackNode { rest: self, element: Rc::new(element), } .into(), ) } fn vec(self) -> StackVecWrapped<'a, Ctx, A> { Ctx::T::ibind((vec![], self), |(mut vec, stack)| match stack { Nullable::Null(_) => Ctx::T::pure(IState::Done(Ok(vec))), Nullable::NotNull(point) => Ctx::T::fmap( |resolved| { let node = match resolved { Ok(node) => node, Err(error) => { return IState::Done(Err(error)); } }; vec.push(node.element.clone()); IState::Pending((vec, node.rest.clone())) }, point.resolve(), ), }) } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> InlineableFactory for StackNodeFactory<'a, Ctx, A> where A::Fctr: InlineableFactory, { } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> FixedSizeFactory for StackNodeFactory<'a, Ctx, A> where A::Fctr: FixedSizeFactory, { fn size(&self) -> usize { Stack::<'a, Ctx, A>::SIZE + self.element_factory.size() } } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ConstSizeFactory for StackNodeFactory<'a, Ctx, A> where A::Fctr: ConstSizeFactory, { const SIZE: usize = Stack::<'a, Ctx, A>::SIZE + A::Fctr::SIZE; } #[cfg(test)] mod tests { use std::rc::Rc; use super::*; use crate::std::atomic::atomic_object::*; use crate::std::atomic::plain::*; use crate::testing::counted::*; use crate::testing::traced::*; use crate::testing::*; type T = Stack<'static, Ctx, AtomicObject>; fn unstack( stack: &T, ) -> Result>, StackFaiure<'static, TestContextPlain, AtomicObject>> { Ok(stack .clone() .vec()? .iter() .map(|plain| plain.raw()) .collect()) } fn make_stack() -> T { let stack: T = Stack::empty(Plain::f()); let stack: T = stack.add(Plain::from_slice(b"A0").into()); let stack: T = stack.add(Plain::from_slice(b"B1").into()); let stack: T = stack.add(Plain::from_slice(b"C2").into()); stack } fn validate_stack(stack: &T) { let mut vec: Vec> = unstack(stack).unwrap(); vec.reverse(); assert_eq!(vec, vec![b"A0".to_vec(), b"B1".to_vec(), b"C2".to_vec()]); } #[test] fn test_stack() -> Result<(), StackFaiure<'static, TestContextPlain, AtomicObject>> { let stack: T = make_stack(); validate_stack(&stack); let stack: T = reparse(stack.into()); validate_stack(&stack); Ok(()) } #[test] fn test_counted() -> Result<(), point::PointParseError> { let stack: T = make_stack(); let count = stack.clone().vec().count(); assert_eq!(count, 0); let stack: T = Rc::new(stack).delay()?; let count = stack.clone().vec().count(); assert_eq!(count, 3); Ok(()) } #[test] fn test_traced() -> Result<(), point::PointParseError> { let stack: T = make_stack(); let traced = stack.clone().vec(); assert_eq!(traced.length(), 0); assert_eq!(traced.width(), 0); assert_eq!(format!("{}", traced.t), "."); let stack: T = Rc::new(stack).trace()?; let traced = stack.clone().vec(); assert_eq!(traced.length(), 3); assert_eq!(traced.width(), 1); assert_eq!(format!("{}", traced.t), "( ? -> ? -> ? )"); Ok(()) } }