diff --git a/src/std/cast.rs b/src/std/cast.rs index 8ada93b..670f183 100644 --- a/src/std/cast.rs +++ b/src/std/cast.rs @@ -3,6 +3,8 @@ //! //! p.s. the implementation is horrific. +use std::convert::identity; + use super::typeless::*; use crate::core::*; use crate::std::*; @@ -107,15 +109,23 @@ impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx> where Ctx::LookupError<'a>: From>, { - /// Re-parse the object as if it is of a specific type. Has potential to break topology. - pub fn cast>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { + pub fn cast_full>( + &self, + factory: A::Fctr, + map_resolver: impl FnOnce(Rc>) -> Rc>, + ) -> CastResult<'a, Ctx, A> { factory.parse_slice( &self.bytes(), - Rc::new(CastResolver { + map_resolver(Rc::new(CastResolver { points: self.points_vec(), - }), + })), ) } + + /// Re-parse the object as if it is of a specific type. Has potential to break topology. + pub fn cast>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { + self.cast_full(factory, identity) + } } impl<'a, Ctx: Context> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> diff --git a/src/std/collections/stack.rs b/src/std/collections/stack.rs index 2c8cef7..0f9c560 100644 --- a/src/std/collections/stack.rs +++ b/src/std/collections/stack.rs @@ -206,16 +206,19 @@ where #[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::*; - type T = Stack<'static, TestContext, AtomicObject>; + type T = Stack<'static, Ctx, AtomicObject>; fn unstack( - stack: &T, - ) -> Result>, StackFaiure<'static, TestContext, AtomicObject>> { + stack: &T, + ) -> Result>, StackFaiure<'static, TestContextPlain, AtomicObject>> { Ok(stack .clone() .vec()? @@ -224,32 +227,43 @@ mod tests { .collect()) } - fn make_stack() -> T { - let stack: T = Stack::empty(Plain::f()); + 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()); + 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) { + 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, TestContext, AtomicObject>> { - let stack: T = make_stack(); + fn test_stack() -> Result<(), StackFaiure<'static, TestContextPlain, AtomicObject>> { + let stack: T = make_stack(); validate_stack(&stack); - let stack: T = reparse(stack.into()); + 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(()) + } } diff --git a/src/testing.rs b/src/testing.rs index 7028d30..455452a 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,13 +1,15 @@ +pub mod counted; + use std::error::Error; use std::fmt::Display; use std::rc::Rc; use crate::core::*; use crate::func::*; -use crate::std::cast::CastError; +use crate::std::cast::*; use sha2::{Digest, Sha256}; -pub struct TestContext; +pub struct TestContextPlain; #[derive(Debug)] pub enum TestLookupError<'a> { @@ -47,7 +49,7 @@ impl<'a> Display for TestLookupError<'a> { impl<'a> Error for TestLookupError<'a> {} -impl Context for TestContext { +impl Context for TestContextPlain { type T = classes::solo::SoloClass; type LookupError<'a> = TestLookupError<'a>; @@ -61,13 +63,13 @@ impl Context for TestContext { pub struct EmptyResolver; -impl<'a> Resolver<'a, TestContext> for EmptyResolver { - fn resolve(self: std::rc::Rc, address: Address) -> HashResolution<'a, TestContext> { +impl<'a> Resolver<'a, TestContextPlain> for EmptyResolver { + fn resolve(self: std::rc::Rc, address: Address) -> HashResolution<'a, TestContextPlain> { Err(TestLookupError::EmptyResolverAccess(address)) } } -pub fn reparse<'a, A: Mentionable<'a, TestContext>>(mentionable: Rc) -> A { +pub fn reparse<'a, A: Mentionable<'a, TestContextPlain>>(mentionable: Rc) -> A { let factory = mentionable.factory(); TypelessMentionable::from_typed(mentionable) .cast(factory) diff --git a/src/testing/counted.rs b/src/testing/counted.rs new file mode 100644 index 0000000..d1075c6 --- /dev/null +++ b/src/testing/counted.rs @@ -0,0 +1,204 @@ +use std::cmp::max; + +use super::*; +use crate::core::*; +use crate::func::*; + +pub struct TestContextCounted; + +impl Context for TestContextCounted { + type T = CountedClass; + + type LookupError<'a> = TestLookupError<'a>; + + fn hash(s: &[u8]) -> Hash { + TestContextPlain::hash(s) + } +} + +pub struct CountedClass; + +pub struct Counted { + a: A, + n: usize, +} + +trait WithCount: Sized { + fn with_count(self, n: usize) -> Counted; +} + +impl WithCount for A { + fn with_count(self, n: usize) -> Counted { + Counted { a: self, n } + } +} + +impl Counted { + fn add(self, n: usize) -> Self { + Counted { + a: self.a, + n: self.n + n, + } + } + + pub fn count(&self) -> usize { + self.n + } +} + +impl WeakFunctor for CountedClass { + type F<'a, A: 'a> = Counted; +} + +impl Functor for CountedClass { + fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> + where + Self: 'a, + { + f(fa.a).with_count(fa.n) + } + + fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> + where + Self: 'a, + { + b.with_count(fa.n) + } + + fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> + where + Self: 'a, + { + ().with_count(fa.n) + } +} + +impl ApplicativeSeq for CountedClass { + fn seq<'a, A: 'a, B: 'a>( + ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, + fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + (ff.a)(fa.a).with_count(max(ff.n, fa.n)) + } +} + +impl ApplicativeLA2 for CountedClass { + fn la2<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(A, B) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + f(fa.a, fb.a).with_count(max(fa.n, fb.n)) + } +} + +impl ApplicativeTuple for CountedClass { + fn tuple<'a, A: 'a, B: 'a>((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> + where + Self: 'a, + { + (fa.a, fb.a).with_count(max(fa.n, fb.n)) + } +} + +impl Applicative for CountedClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + a.with_count(0) + } + + fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> + where + Self: 'a, + { + fb.a.with_count(max(fa.n, fb.n)) + } + + fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> + where + Self: 'a, + { + fa.a.with_count(max(fa.n, fb.n)) + } +} + +impl Monad for CountedClass { + fn bind<'a, A: 'a, B: 'a>( + fa: Self::F<'a, A>, + f: impl 'a + FnOnce(A) -> Self::F<'a, B>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + f(fa.a).add(fa.n) + } + + fn ibind<'a, A: 'a, B: 'a>( + mut a: A, + mut f: impl 'a + FnMut(A) -> Self::F<'a, IState>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + let mut n = 0; + loop { + let fa = f(a); + n += fa.n; + match fa.a { + IState::Pending(next_a) => a = next_a, + IState::Done(b) => return b.with_count(n), + } + } + } + + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> + where + Self::F<'a, A>: 'a, + Self: 'a, + { + ffa.a.add(ffa.n) + } +} + +struct CountedResolver<'a> { + resolver: Rc>, +} + +impl<'a> CountedResolver<'a> { + fn new( + resolver: Rc>, + ) -> Rc> { + Rc::new(Self { resolver }) + } +} + +impl<'a> Resolver<'a, TestContextCounted> for CountedResolver<'a> { + fn resolve(self: Rc, address: Address) -> HashResolution<'a, TestContextCounted> { + CountedClass::fmap( + |resolved| { + let (src, resolver) = resolved?; + let delayed: Rc> = + Rc::new(CountedResolver { resolver }); + Ok((src, delayed)) + }, + self.resolver.clone().resolve(address), + ) + .add(1) + } +} + +pub trait Delayable<'a>: Mentionable<'a, TestContextCounted> + Sized { + fn delay(self: Rc) -> CastResult<'a, TestContextCounted, Self>; +} + +impl<'a, A: Mentionable<'a, TestContextCounted>> Delayable<'a> for A { + fn delay(self: Rc) -> CastResult<'a, TestContextCounted, Self> { + let factory = self.factory(); + TypelessMentionable::from_typed(self).cast_full(factory, CountedResolver::new) + } +}