TestContextCounted
This commit is contained in:
		
							parent
							
								
									1aa0cff0b6
								
							
						
					
					
						commit
						c91c8f5a0d
					
				| @ -3,6 +3,8 @@ | |||||||
| //!
 | //!
 | ||||||
| //! p.s. the implementation is horrific.
 | //! p.s. the implementation is horrific.
 | ||||||
| 
 | 
 | ||||||
|  | use std::convert::identity; | ||||||
|  | 
 | ||||||
| use super::typeless::*; | use super::typeless::*; | ||||||
| use crate::core::*; | use crate::core::*; | ||||||
| use crate::std::*; | use crate::std::*; | ||||||
| @ -107,15 +109,23 @@ impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx> | |||||||
| where | where | ||||||
|     Ctx::LookupError<'a>: From<CastError<'a>>, |     Ctx::LookupError<'a>: From<CastError<'a>>, | ||||||
| { | { | ||||||
|     /// Re-parse the object as if it is of a specific type. Has potential to break topology.
 |     pub fn cast_full<A: Mentionable<'a, Ctx>>( | ||||||
|     pub fn cast<A: Mentionable<'a, Ctx>>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { |         &self, | ||||||
|  |         factory: A::Fctr, | ||||||
|  |         map_resolver: impl FnOnce(Rc<dyn Resolver<'a, Ctx>>) -> Rc<dyn Resolver<'a, Ctx>>, | ||||||
|  |     ) -> CastResult<'a, Ctx, A> { | ||||||
|         factory.parse_slice( |         factory.parse_slice( | ||||||
|             &self.bytes(), |             &self.bytes(), | ||||||
|             Rc::new(CastResolver { |             map_resolver(Rc::new(CastResolver { | ||||||
|                 points: self.points_vec(), |                 points: self.points_vec(), | ||||||
|             }), |             })), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Re-parse the object as if it is of a specific type. Has potential to break topology.
 | ||||||
|  |     pub fn cast<A: Mentionable<'a, Ctx>>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { | ||||||
|  |         self.cast_full(factory, identity) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a, Ctx: Context> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> | impl<'a, Ctx: Context> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> | ||||||
|  | |||||||
| @ -206,16 +206,19 @@ where | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|  |     use std::rc::Rc; | ||||||
|  | 
 | ||||||
|     use super::*; |     use super::*; | ||||||
|     use crate::std::atomic::atomic_object::*; |     use crate::std::atomic::atomic_object::*; | ||||||
|     use crate::std::atomic::plain::*; |     use crate::std::atomic::plain::*; | ||||||
|  |     use crate::testing::counted::*; | ||||||
|     use crate::testing::*; |     use crate::testing::*; | ||||||
| 
 | 
 | ||||||
|     type T = Stack<'static, TestContext, AtomicObject<Plain>>; |     type T<Ctx> = Stack<'static, Ctx, AtomicObject<Plain>>; | ||||||
| 
 | 
 | ||||||
|     fn unstack( |     fn unstack( | ||||||
|         stack: &T, |         stack: &T<TestContextPlain>, | ||||||
|     ) -> Result<Vec<Vec<u8>>, StackFaiure<'static, TestContext, AtomicObject<Plain>>> { |     ) -> Result<Vec<Vec<u8>>, StackFaiure<'static, TestContextPlain, AtomicObject<Plain>>> { | ||||||
|         Ok(stack |         Ok(stack | ||||||
|             .clone() |             .clone() | ||||||
|             .vec()? |             .vec()? | ||||||
| @ -224,32 +227,43 @@ mod tests { | |||||||
|             .collect()) |             .collect()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn make_stack() -> T { |     fn make_stack<Ctx: 'static + Context>() -> T<Ctx> { | ||||||
|         let stack: T = Stack::empty(Plain::f()); |         let stack: T<Ctx> = Stack::empty(Plain::f()); | ||||||
| 
 | 
 | ||||||
|         let stack: T = stack.add(Plain::from_slice(b"A0").into()); |         let stack: T<Ctx> = stack.add(Plain::from_slice(b"A0").into()); | ||||||
|         let stack: T = stack.add(Plain::from_slice(b"B1").into()); |         let stack: T<Ctx> = stack.add(Plain::from_slice(b"B1").into()); | ||||||
|         let stack: T = stack.add(Plain::from_slice(b"C2").into()); |         let stack: T<Ctx> = stack.add(Plain::from_slice(b"C2").into()); | ||||||
| 
 | 
 | ||||||
|         stack |         stack | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn validate_stack(stack: &T) { |     fn validate_stack(stack: &T<TestContextPlain>) { | ||||||
|         let mut vec: Vec<Vec<u8>> = unstack(stack).unwrap(); |         let mut vec: Vec<Vec<u8>> = unstack(stack).unwrap(); | ||||||
|         vec.reverse(); |         vec.reverse(); | ||||||
|         assert_eq!(vec, vec![b"A0".to_vec(), b"B1".to_vec(), b"C2".to_vec()]); |         assert_eq!(vec, vec![b"A0".to_vec(), b"B1".to_vec(), b"C2".to_vec()]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_stack() -> Result<(), StackFaiure<'static, TestContext, AtomicObject<Plain>>> { |     fn test_stack() -> Result<(), StackFaiure<'static, TestContextPlain, AtomicObject<Plain>>> { | ||||||
|         let stack: T = make_stack(); |         let stack: T<TestContextPlain> = make_stack(); | ||||||
| 
 | 
 | ||||||
|         validate_stack(&stack); |         validate_stack(&stack); | ||||||
| 
 | 
 | ||||||
|         let stack: T = reparse(stack.into()); |         let stack: T<TestContextPlain> = reparse(stack.into()); | ||||||
| 
 | 
 | ||||||
|         validate_stack(&stack); |         validate_stack(&stack); | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         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(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,15 @@ | |||||||
|  | pub mod counted; | ||||||
|  | 
 | ||||||
| use std::error::Error; | use std::error::Error; | ||||||
| use std::fmt::Display; | use std::fmt::Display; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| use crate::core::*; | use crate::core::*; | ||||||
| use crate::func::*; | use crate::func::*; | ||||||
| use crate::std::cast::CastError; | use crate::std::cast::*; | ||||||
| use sha2::{Digest, Sha256}; | use sha2::{Digest, Sha256}; | ||||||
| 
 | 
 | ||||||
| pub struct TestContext; | pub struct TestContextPlain; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum TestLookupError<'a> { | pub enum TestLookupError<'a> { | ||||||
| @ -47,7 +49,7 @@ impl<'a> Display for TestLookupError<'a> { | |||||||
| 
 | 
 | ||||||
| impl<'a> Error for TestLookupError<'a> {} | impl<'a> Error for TestLookupError<'a> {} | ||||||
| 
 | 
 | ||||||
| impl Context for TestContext { | impl Context for TestContextPlain { | ||||||
|     type T = classes::solo::SoloClass; |     type T = classes::solo::SoloClass; | ||||||
| 
 | 
 | ||||||
|     type LookupError<'a> = TestLookupError<'a>; |     type LookupError<'a> = TestLookupError<'a>; | ||||||
| @ -61,13 +63,13 @@ impl Context for TestContext { | |||||||
| 
 | 
 | ||||||
| pub struct EmptyResolver; | pub struct EmptyResolver; | ||||||
| 
 | 
 | ||||||
| impl<'a> Resolver<'a, TestContext> for EmptyResolver { | impl<'a> Resolver<'a, TestContextPlain> for EmptyResolver { | ||||||
|     fn resolve(self: std::rc::Rc<Self>, address: Address) -> HashResolution<'a, TestContext> { |     fn resolve(self: std::rc::Rc<Self>, address: Address) -> HashResolution<'a, TestContextPlain> { | ||||||
|         Err(TestLookupError::EmptyResolverAccess(address)) |         Err(TestLookupError::EmptyResolverAccess(address)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn reparse<'a, A: Mentionable<'a, TestContext>>(mentionable: Rc<A>) -> A { | pub fn reparse<'a, A: Mentionable<'a, TestContextPlain>>(mentionable: Rc<A>) -> A { | ||||||
|     let factory = mentionable.factory(); |     let factory = mentionable.factory(); | ||||||
|     TypelessMentionable::from_typed(mentionable) |     TypelessMentionable::from_typed(mentionable) | ||||||
|         .cast(factory) |         .cast(factory) | ||||||
|  | |||||||
							
								
								
									
										204
									
								
								src/testing/counted.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								src/testing/counted.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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: A, | ||||||
|  |     n: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | trait WithCount: Sized { | ||||||
|  |     fn with_count(self, n: usize) -> Counted<Self>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<A> WithCount for A { | ||||||
|  |     fn with_count(self, n: usize) -> Counted<Self> { | ||||||
|  |         Counted { a: self, n } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<A> Counted<A> { | ||||||
|  |     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<A>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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<A, B>>, | ||||||
|  |     ) -> 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<dyn Resolver<'a, TestContextCounted>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> CountedResolver<'a> { | ||||||
|  |     fn new( | ||||||
|  |         resolver: Rc<dyn Resolver<'a, TestContextCounted>>, | ||||||
|  |     ) -> Rc<dyn Resolver<'a, TestContextCounted>> { | ||||||
|  |         Rc::new(Self { resolver }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> Resolver<'a, TestContextCounted> for CountedResolver<'a> { | ||||||
|  |     fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, TestContextCounted> { | ||||||
|  |         CountedClass::fmap( | ||||||
|  |             |resolved| { | ||||||
|  |                 let (src, resolver) = resolved?; | ||||||
|  |                 let delayed: Rc<dyn Resolver<'a, TestContextCounted>> = | ||||||
|  |                     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<Self>) -> CastResult<'a, TestContextCounted, Self>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a, A: Mentionable<'a, TestContextCounted>> Delayable<'a> for A { | ||||||
|  |     fn delay(self: Rc<Self>) -> CastResult<'a, TestContextCounted, Self> { | ||||||
|  |         let factory = self.factory(); | ||||||
|  |         TypelessMentionable::from_typed(self).cast_full(factory, CountedResolver::new) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user