TestContextCounted

This commit is contained in:
AF 2023-04-23 02:46:10 +00:00
parent 1aa0cff0b6
commit c91c8f5a0d
4 changed files with 252 additions and 22 deletions

View File

@ -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>>

View File

@ -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(())
}
} }

View File

@ -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
View 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)
}
}