//! Basic implementation of a stack/linked list. use crate::func::context::*; use crate::rcore::*; use crate::rstd::{inlining::*, nullable::*, point::*, *}; /// Node containing a (nullable) reference to the next node and an element. pub struct StackNode<'a, Ctx: Context<'a>, 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: Context<'a>, A: Mentionable<'a, Ctx>> { element_factory: A::Fctr, } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> StackNodeFactory<'a, Ctx, A> { fn new(factory: A::Fctr) -> Self { StackNodeFactory { element_factory: factory, } } } impl<'a, Ctx: Context<'a>, 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: Context<'a>, 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_typed(&self, points: &mut impl TakesPoints<'a, Ctx>) { self.rest.points_typed(points); self.element.points_typed(points); } } impl<'a, Ctx: Context<'a>, 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: Context<'a>, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> for StackNodeFactory<'a, Ctx, A> { type Mtbl = StackNode<'a, Ctx, A>; type ParseError = StackParseError>; 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: Context<'a>, 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: Context<'a>, 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::iterate_mut((vec![], self), |(mut vec, stack)| match stack { Nullable::Null(_) => Ctx::pure(ControlFlow::Break(Ok(vec))), Nullable::NotNull(point) => Ctx::fmap(point.resolve(), |resolved| { let node = match resolved { Ok(node) => node, Err(error) => { return ControlFlow::Break(Err(error)); } }; vec.push(node.element.clone()); ControlFlow::Continue((vec, node.rest.clone())) }), }) } } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> InlineableFactory for StackNodeFactory<'a, Ctx, A> where A::Fctr: InlineableFactory, { } impl<'a, Ctx: Context<'a>, 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: Context<'a>, 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 crate::rstd::{ atomic::{atomic_object::*, plain::*}, tracing::*, }; use crate::testing::{counted::*, traced::*, *}; use super::*; 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.effect), "."); 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.effect), "( ? > ? > ? )"); Ok(()) } #[test] fn test_rendered() -> Result<(), point::PointParseError> { let stack: T = make_stack(); let rendered = stack.clone().vec().render(); assert_eq!(rendered.length(), 0); assert_eq!(rendered.width(), 0); assert_eq!(format!("{}", rendered), "."); let stack: T = Rc::new(stack).trace()?; let rendered = stack.clone().vec().render(); assert_eq!(rendered.length(), 3); assert_eq!(rendered.width(), 1); assert_eq!(format!("{}", rendered), "( ? > ? > ? )"); Ok(()) } }