308 lines
9.7 KiB
Rust
308 lines
9.7 KiB
Rust
//! Basic implementation of a stack/linked list.
|
|
|
|
use crate::func::{context::*, controlflow::ControlFlow};
|
|
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: A,
|
|
}
|
|
|
|
/// 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>>;
|
|
|
|
#[derive(Clone)]
|
|
pub struct StackNodeFactory<F> {
|
|
element_factory: F,
|
|
}
|
|
|
|
impl<F> StackNodeFactory<F> {
|
|
fn new(factory: F) -> 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::Fctr>;
|
|
|
|
fn factory(&self) -> Self::Fctr {
|
|
StackNodeFactory::new(self.element.factory())
|
|
}
|
|
|
|
fn points_typed(&self, points: &mut impl PointsVisitor<'a, Ctx>) {
|
|
self.rest.points_typed(points);
|
|
self.element.points_typed(points);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum StackParseError<ElementParseError: Error> {
|
|
Point(PointParseError),
|
|
Element(ElementParseError),
|
|
}
|
|
|
|
impl<E: Error> From<PointParseError> for StackParseError<E> {
|
|
fn from(value: PointParseError) -> Self {
|
|
Self::Point(value)
|
|
}
|
|
}
|
|
|
|
impl<ElementParseError: Error> Display for StackParseError<ElementParseError> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Point(ppe) => {
|
|
write!(f, "can't parse stack's next pointer: {}", ppe)
|
|
}
|
|
Self::Element(epe) => {
|
|
write!(f, "can't parse stack's element: {}", epe)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<ElementParseError: Error> Error for StackParseError<ElementParseError> {}
|
|
|
|
impl<F> StackNodeFactory<F> {
|
|
fn parse_point<'a, Ctx: Context<'a>, I: InCtx<'a, Ctx>>(
|
|
&self,
|
|
inctx: I,
|
|
) -> IParseResult<'a, Ctx, NullableFactory<Self>, I>
|
|
where
|
|
F: FactoryBase<'a, Ctx>,
|
|
{
|
|
NullableFactory::new(self.clone()).ideserialize(inctx)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: FactoryBase<'a, Ctx>> FactoryBase<'a, Ctx> for StackNodeFactory<F> {
|
|
type Mtbl = StackNode<'a, Ctx, F::Mtbl>;
|
|
|
|
type ParseError = StackParseError<ParseError<'a, Ctx, F>>;
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for StackNodeFactory<F> {
|
|
fn deserialize(&self, inctx: impl InCtx<'a, Ctx>) -> ParseResult<'a, Ctx, Self> {
|
|
let (rest, inctx) = self.parse_point(inctx)?;
|
|
let element = self
|
|
.element_factory
|
|
.deserialize(inctx)
|
|
.map_err(StackParseError::Element)?;
|
|
Ok(StackNode { rest, element })
|
|
}
|
|
|
|
fn extend(&self, mut mentionable: Self::Mtbl, tail: &[u8]) -> ParseResult<'a, Ctx, Self> {
|
|
mentionable.element = self
|
|
.element_factory
|
|
.extend(mentionable.element, tail)
|
|
.map_err(StackParseError::Element)?;
|
|
Ok(mentionable)
|
|
}
|
|
}
|
|
|
|
/// See [`StackVecResult`].
|
|
pub type StackFaiure<'a, Ctx, A> = ResolutionFailure<'a, Ctx, StackNode<'a, Ctx, A>>;
|
|
|
|
/// See [`StackVecWrapped`].
|
|
pub type StackVecResult<'a, Ctx, A> = Result<Vec<A>, StackFaiure<'a, Ctx, A>>;
|
|
|
|
/// See [`ExtStackClone::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;
|
|
}
|
|
|
|
/// Extention trait with helper methods for [Stack]s.
|
|
pub trait ExtStackClone<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx> + Clone>:
|
|
Mentionable<'a, Ctx>
|
|
{
|
|
/// 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,
|
|
}
|
|
.into(),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx> + Clone> ExtStackClone<'a, Ctx, A>
|
|
for Stack<'a, Ctx, A>
|
|
{
|
|
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) => point.resolve_map(|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>, F: InlineableFactory<'a, Ctx>> InlineableFactory<'a, Ctx>
|
|
for StackNodeFactory<F>
|
|
{
|
|
fn extension_error(&self, tail: &[u8]) -> Self::ParseError {
|
|
StackParseError::Element(self.element_factory.extension_error(tail))
|
|
}
|
|
|
|
fn ideserialize<I: InCtx<'a, Ctx>>(&self, inctx: I) -> IParseResult<'a, Ctx, Self, I> {
|
|
let (rest, inctx) = self.parse_point(inctx)?;
|
|
let (element, inctx) = self
|
|
.element_factory
|
|
.ideserialize(inctx)
|
|
.map_err(StackParseError::Element)?;
|
|
Ok((StackNode { rest, element }, inctx))
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: FixedSizeFactory<'a, Ctx>> FixedSizeFactory<'a, Ctx>
|
|
for StackNodeFactory<F>
|
|
{
|
|
fn size(&self) -> usize {
|
|
Stack::<'a, Ctx, F::Mtbl>::SIZE + self.element_factory.size()
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: ConstSizeFactory<'a, Ctx>> ConstSizeFactory<'a, Ctx>
|
|
for StackNodeFactory<F>
|
|
{
|
|
const SIZE: usize = Stack::<'a, Ctx, F::Mtbl>::SIZE + F::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<Ctx> = Stack<'static, Ctx, AtomicObject<Plain>>;
|
|
|
|
fn unstack(
|
|
stack: &T<TestContextPlain>,
|
|
) -> Result<Vec<Vec<u8>>, StackFaiure<'static, TestContextPlain, AtomicObject<Plain>>> {
|
|
Ok(stack
|
|
.clone()
|
|
.vec()?
|
|
.iter()
|
|
.map(|plain| plain.raw())
|
|
.collect())
|
|
}
|
|
|
|
fn make_stack<Ctx: Context<'static>>() -> T<Ctx> {
|
|
let stack: T<Ctx> = Stack::empty(Plain::f());
|
|
|
|
let stack: T<Ctx> = stack.add(Plain::from_slice(b"A0").into());
|
|
let stack: T<Ctx> = stack.add(Plain::from_slice(b"B1").into());
|
|
let stack: T<Ctx> = stack.add(Plain::from_slice(b"C2").into());
|
|
|
|
stack
|
|
}
|
|
|
|
fn validate_stack(stack: &T<TestContextPlain>) {
|
|
let mut vec: Vec<Vec<u8>> = 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<Plain>>> {
|
|
let stack: T<TestContextPlain> = make_stack();
|
|
|
|
validate_stack(&stack);
|
|
|
|
let stack: T<TestContextPlain> = reparse(stack.into());
|
|
|
|
validate_stack(&stack);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_counted() -> Result<(), point::PointParseError> {
|
|
let stack: T<TestContextCounted> = make_stack();
|
|
let count = stack.clone().vec().count();
|
|
assert_eq!(count, 0);
|
|
let stack: T<TestContextCounted> = 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<TestContextTraced> = 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<TestContextTraced> = 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<TestContextTraced> = 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<TestContextTraced> = 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(())
|
|
}
|
|
}
|