From d5bcd53335d5022a84fa67de80bb6ea7a2e09356 Mon Sep 17 00:00:00 2001 From: timofey Date: Fri, 21 Apr 2023 17:02:54 +0000 Subject: [PATCH] cast --- src/core.rs | 113 ++++++++++++++------- src/std.rs | 236 ++++++++++++++++++++++++++++++++++++++++---- src/std/atomic.rs | 10 +- src/std/cast.rs | 61 ++++++++++++ src/std/nullable.rs | 77 +++++++++++++++ 5 files changed, 442 insertions(+), 55 deletions(-) create mode 100644 src/std/cast.rs create mode 100644 src/std/nullable.rs diff --git a/src/core.rs b/src/core.rs index d4b29d4..932e9c2 100644 --- a/src/core.rs +++ b/src/core.rs @@ -5,11 +5,32 @@ use crate::func::*; pub trait Context { type T: Monad; + type LookupError: Error; + fn hash(s: &[u8]) -> Hash; } +pub enum ResolutionError { + Lookup(L), + Parse(P), +} + +pub type ResolutionResult<'a, Ctx, A> = Result< + Rc, + ResolutionError< + ::LookupError, + <>::Fctr as Factory<'a, Ctx>>::ParseError, + >, +>; + +pub type Wrapped<'a, Ctx, A> = <::T as WeakFunctor>::F<'a, A>; + +pub type Resolution<'a, Ctx, A> = Wrapped<'a, Ctx, ResolutionResult<'a, Ctx, A>>; + pub const HASH_SIZE: usize = 32; +pub const HASH_ZEROS: [u8; HASH_SIZE] = [0; HASH_SIZE]; + pub type Hash = [u8; HASH_SIZE]; pub trait Serializer { @@ -45,39 +66,45 @@ pub trait Mentionable<'a, Ctx: 'a + Context>: 'a + Serializable { fn points(&self) -> Vec>>; } +pub type HashResolution<'a, Ctx> = + Wrapped<'a, Ctx, Result<(Vec, Rc>), ::LookupError>>; + +#[derive(Clone, Copy)] +pub struct Address { + pub point: Hash, + pub index: usize, +} + +pub trait Resolver<'a, Ctx: 'a + Context>: 'a { + fn resolve(self: Rc, address: Address) -> HashResolution<'a, Ctx>; +} + pub trait Deserializer { fn read_n(&mut self, n: usize) -> &[u8]; - fn read_all(&mut self, n: usize) -> &[u8]; + fn read_all(&mut self) -> &[u8]; + fn tell(&self) -> usize; } -pub trait ExtDeserialiser { - fn read_n_const(&mut self) -> Result<[u8; N], &[u8]>; -} - -impl ExtDeserialiser for D { - fn read_n_const(&mut self) -> Result<[u8; N], &[u8]> { - let slice = self.read_n(N); - match slice.try_into() { - Ok(array) => Ok(array), - Err(_) => Err(slice), - } - } -} +pub type ParseResult<'a, Ctx, F> = + Result<>::Mtbl, >::ParseError>; pub trait Factory<'a, Ctx: 'a + Context>: Clone + 'a { type Mtbl: Mentionable<'a, Ctx, Fctr = Self>; - type ParseError: Error; + type ParseError: 'a + Error; fn deserialize( &self, deserializer: &mut dyn Deserializer, - ) -> Result; + resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self>; + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError; } pub trait Origin<'a, Ctx: 'a + Context>: 'a { type Mtbl: Mentionable<'a, Ctx>; fn factory(&self) -> >::Fctr; - fn resolve(&self) -> <::T as WeakFunctor>::F<'a, Rc>; + fn resolve(self: Rc) -> Resolution<'a, Ctx, Self::Mtbl>; } struct LocalOrigin(Rc); @@ -89,8 +116,8 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for LocalOr self.0.factory() } - fn resolve(&self) -> <::T as WeakFunctor>::F<'a, Rc> { - ::pure(self.0.clone()) + fn resolve(self: Rc) -> Resolution<'a, Ctx, Self::Mtbl> { + ::pure(Ok(self.0.clone())) } } @@ -129,8 +156,8 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { Self::from_fields(point, Rc::new(origin)) } - pub fn resolve(&self) -> <::T as WeakFunctor>::F<'a, Rc> { - self.origin.resolve() + pub fn resolve(&self) -> Resolution<'a, Ctx, A> { + self.origin.clone().resolve() } } @@ -154,10 +181,14 @@ pub struct TypelessMentionable<'a, Ctx: 'a + Context> { type TypelessParsed<'a, Ctx> = Result, Box>; -type TypelessDeserialize<'a, Ctx> = dyn 'a + Fn(&mut dyn Deserializer) -> TypelessParsed<'a, Ctx>; +type TypelessDeserialize<'a, Ctx> = + dyn 'a + Fn(&mut dyn Deserializer, Rc>) -> TypelessParsed<'a, Ctx>; + +type TypelessUnexpectedTail<'a> = dyn 'a + Fn(&[u8]) -> TypelessError<'a>; pub struct TypelessFactory<'a, Ctx: 'a + Context> { t_deserialize: Rc>, + t_unexpected_tail: Rc>, } impl<'a, Ctx: 'a + Context> Serializable for TypelessMentionable<'a, Ctx> { @@ -186,6 +217,7 @@ impl<'a, Ctx: 'a + Context> Clone for TypelessFactory<'a, Ctx> { fn clone(&self) -> Self { Self { t_deserialize: self.t_deserialize.clone(), + t_unexpected_tail: self.t_unexpected_tail.clone(), } } } @@ -209,17 +241,22 @@ impl<'a, Ctx: 'a + Context> Factory<'a, Ctx> for TypelessFactory<'a, Ctx> { fn deserialize( &self, deserializer: &mut dyn Deserializer, - ) -> Result { - match (self.t_deserialize)(deserializer) { + resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self> { + match (self.t_deserialize)(deserializer, resolver) { Ok(mentionable) => Ok(mentionable), Err(error) => Err(TypelessError(error)), } } + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { + (self.t_unexpected_tail)(tail) + } } impl<'a, Ctx: 'a + Context> TypelessMentionable<'a, Ctx> { - pub fn from_mentionable>(mentionable: Rc) -> Self { - let factory = TypelessFactory::from_factory(mentionable.factory()); + pub fn from_typed>(mentionable: Rc) -> Self { + let factory = TypelessFactory::from_typed(mentionable.factory()); let topology = mentionable.topology(); let points = mentionable.points(); TypelessMentionable { @@ -232,16 +269,24 @@ impl<'a, Ctx: 'a + Context> TypelessMentionable<'a, Ctx> { } impl<'a, Ctx: 'a + Context> TypelessFactory<'a, Ctx> { - pub fn from_factory>(factory: F) -> Self { + pub fn from_typed>(factory: F) -> Self { + let tail_factory = factory.clone(); TypelessFactory { - t_deserialize: Rc::new( - move |deserializer| match factory.deserialize(deserializer) { - Ok(mentionable) => { - Ok(TypelessMentionable::from_mentionable(Rc::new(mentionable))) - } + t_deserialize: Rc::new(move |deserializer, resolver| { + match factory.deserialize(deserializer, resolver) { + Ok(mentionable) => Ok(TypelessMentionable::from_typed(Rc::new(mentionable))), Err(error) => Err(Box::new(error)), - }, - ), + } + }), + t_unexpected_tail: Rc::new(move |tail| { + TypelessError::from_typed(tail_factory.unexpected_tail(tail)) + }), } } } + +impl<'a> TypelessError<'a> { + pub fn from_typed(error: E) -> Self { + TypelessError(Box::new(error)) + } +} diff --git a/src/std.rs b/src/std.rs index 7f1b30e..fda58d6 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,6 +1,9 @@ pub mod atomic; +pub mod cast; pub mod inlining; +pub mod nullable; +use std::cmp::min; use std::{error::Error, fmt::Display, rc::Rc}; use crate::core::*; @@ -8,23 +11,38 @@ use crate::func::*; struct WrappedOrigin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { w_factory: A::Fctr, - w_resolve: Box <::T as WeakFunctor>::F<'a, Rc>>, + w_resolve: Box Resolution<'a, Ctx, A>>, } trait MappableOrigin<'a, Ctx: 'a + Context>: Origin<'a, Ctx> { fn map>( self: Rc, - map_mentionable: impl 'a + Clone + Fn(Rc) -> B, + map_ok: impl 'a + Clone + Fn(Rc) -> B, + map_err: impl 'a + + Clone + + Fn( + <>::Fctr as Factory<'a, Ctx>>::ParseError, + ) -> >::ParseError, map_factory: impl 'a + FnOnce(>::Fctr) -> B::Fctr, ) -> WrappedOrigin<'a, Ctx, B>; } fn map_resolve<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>, B: Mentionable<'a, Ctx>>( - resolve: impl 'a + Fn() -> <::T as WeakFunctor>::F<'a, Rc>, - map_mentionable: impl 'a + Fn(Rc) -> B, -) -> <::T as WeakFunctor>::F<'a, Rc> { + resolve: impl 'a + Fn() -> Resolution<'a, Ctx, A>, + map_ok: impl 'a + Fn(Rc) -> B, + map_err: impl 'a + + Fn(>::ParseError) -> >::ParseError, +) -> Resolution<'a, Ctx, B> { Ctx::T::fmap( - move |resolved| Rc::new(map_mentionable(resolved)), + move |resolved| match resolved { + Ok(mentionable) => Ok(Rc::new(map_ok(mentionable))), + Err(ResolutionError::Parse(parse_error)) => { + Err(ResolutionError::Parse(map_err(parse_error))) + } + Err(ResolutionError::Lookup(lookup_error)) => { + Err(ResolutionError::Lookup(lookup_error)) + } + }, resolve(), ) } @@ -32,7 +50,12 @@ fn map_resolve<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>, B: Mentionable<'a impl<'a, Ctx: 'a + Context, O: ?Sized + Origin<'a, Ctx>> MappableOrigin<'a, Ctx> for O { fn map>( self: Rc, - map_mentionable: impl 'a + Clone + Fn(Rc) -> B, + map_ok: impl 'a + Clone + Fn(Rc) -> B, + map_err: impl 'a + + Clone + + Fn( + <>::Fctr as Factory<'a, Ctx>>::ParseError, + ) -> >::ParseError, map_factory: impl 'a + FnOnce(>::Fctr) -> B::Fctr, ) -> WrappedOrigin<'a, Ctx, B> { let origin = self.clone(); @@ -40,11 +63,9 @@ impl<'a, Ctx: 'a + Context, O: ?Sized + Origin<'a, Ctx>> MappableOrigin<'a, Ctx> w_factory: map_factory(self.factory()), w_resolve: Box::new(move || { let origin = origin.clone(); - let map_mentionable = map_mentionable.clone(); - map_resolve( - move || origin.resolve(), - map_mentionable, - ) + let map_ok = map_ok.clone(); + let map_err = map_err.clone(); + map_resolve(move || origin.clone().resolve(), map_ok, map_err) }), } } @@ -57,7 +78,7 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for Wrapped self.w_factory.clone() } - fn resolve(&self) -> <::T as WeakFunctor>::F<'a, Rc> { + fn resolve(self: Rc) -> Resolution<'a, Ctx, A> { (self.w_resolve)() } } @@ -67,8 +88,9 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { Point { point: self.point, origin: Rc::new(self.origin.clone().map( - TypelessMentionable::from_mentionable, - TypelessFactory::from_factory, + TypelessMentionable::from_typed, + TypelessError::from_typed, + TypelessFactory::from_typed, )), } } @@ -121,6 +143,64 @@ impl Display for PointParseError { impl Error for PointParseError {} +impl From<&[u8]> for PointParseError { + fn from(value: &[u8]) -> Self { + PointParseError::WrongLength(value.len()) + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { + fn from_point(address: Address, factory: A::Fctr, resolver: Rc>) -> Self { + Point { + point: address.point, + origin: Rc::new(ResolverOrigin { + r_factory: factory, + r_address: address, + r_resolver: resolver, + }), + } + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> AsRef<[u8]> for Point<'a, Ctx, A> { + fn as_ref(&self) -> &[u8] { + &self.point + } +} + +struct Addresses { + current: usize, +} + +impl Addresses { + fn next<'a>(&mut self, deserializer: &'a mut dyn Deserializer) -> Result { + let point = deserializer.read_n_const::()?; + let address = Address { + point, + index: self.current, + }; + self.current += 1; + Ok(address) + } + + fn next_point<'a, 'b, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>( + &mut self, + deserializer: &'b mut dyn Deserializer, + resolver: Rc>, + factory: A::Fctr, + ) -> Result, &'b [u8]> { + Ok(Point::from_point( + self.next(deserializer)?, + factory, + resolver, + )) + } + + fn start() -> Self { + Addresses { current: 0 } + } +} + impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFactory { type Mtbl = Point<'a, Ctx, F::Mtbl>; @@ -129,10 +209,128 @@ impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFacto fn deserialize( &self, deserializer: &mut dyn Deserializer, - ) -> Result { - match deserializer.read_n_const::() { - Ok(point) => Ok(Point {point, origin: todo!()}), - Err(slice) => Err(PointParseError::WrongLength(slice.len())), + resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self> { + let mut addresses = Addresses::start(); + Ok(addresses.next_point(deserializer, resolver, self.factory.clone())?) + } + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { + PointParseError::WrongLength(HASH_SIZE + tail.len()) + } +} + +struct ResolverOrigin<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> { + r_factory: F, + r_address: Address, + r_resolver: Rc>, +} + +fn _resolve_origin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>( + origin: Rc>, +) -> Resolution<'a, Ctx, A> { + let resolution = origin.r_resolver.clone().resolve(origin.r_address); + Ctx::T::fmap( + move |resolved| match resolved { + Ok((src, resolver)) => match origin.r_factory.parse_slice(&src, resolver) { + Ok(mentionable) => Ok(Rc::new(mentionable)), + Err(parse_error) => Err(ResolutionError::Parse(parse_error)), + }, + Err(lookup_error) => Err(ResolutionError::Lookup(lookup_error)), + }, + resolution, + ) +} + +impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Origin<'a, Ctx> for ResolverOrigin<'a, Ctx, F> { + type Mtbl = F::Mtbl; + + fn factory(&self) -> >::Fctr { + self.r_factory.clone() + } + + fn resolve(self: Rc) -> Resolution<'a, Ctx, Self::Mtbl> { + _resolve_origin(self) + } +} + +struct SliceDeserializer<'a> { + slice: &'a [u8], + pos: usize, +} + +impl<'a> From<&'a [u8]> for SliceDeserializer<'a> { + fn from(value: &'a [u8]) -> Self { + SliceDeserializer { + slice: value, + pos: 0, + } + } +} + +impl<'a> Deserializer for SliceDeserializer<'a> { + fn read_n(&mut self, n: usize) -> &[u8] { + let (left, right) = self.slice.split_at(min(n, self.slice.len())); + self.slice = right; + self.pos += left.len(); + left + } + + fn read_all(&mut self) -> &[u8] { + let left = self.slice; + self.slice = &[]; + self.pos += left.len(); + left + } + + fn tell(&self) -> usize { + self.pos + } +} + +fn _parse_slice<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>( + factory: &A::Fctr, + slice: &[u8], + resolver: Rc>, +) -> ParseResult<'a, Ctx, A::Fctr> { + let mut deserializer = SliceDeserializer::from(slice); + let mentionable = factory.deserialize(&mut deserializer, resolver)?; + let tail = deserializer.read_all(); + if tail.is_empty() { + Ok(mentionable) + } else { + Err(factory.unexpected_tail(tail)) + } +} + +pub trait ExtFactory<'a, Ctx: 'a + Context>: Factory<'a, Ctx> { + fn parse_slice( + &self, + slice: &[u8], + resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self>; +} + +impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> ExtFactory<'a, Ctx> for F { + fn parse_slice( + &self, + slice: &[u8], + resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self> { + _parse_slice::(self, slice, resolver) + } +} + +pub trait ExtDeserializer { + fn read_n_const(&mut self) -> Result<[u8; N], &[u8]>; +} + +impl ExtDeserializer for D { + fn read_n_const(&mut self) -> Result<[u8; N], &[u8]> { + let slice = self.read_n(N); + match slice.try_into() { + Ok(array) => Ok(array), + Err(_) => Err(slice), } } } diff --git a/src/std/atomic.rs b/src/std/atomic.rs index bb5fd88..baec58e 100644 --- a/src/std/atomic.rs +++ b/src/std/atomic.rs @@ -1,10 +1,11 @@ -use std::{error::Error, marker::PhantomData}; +use std::{error::Error, marker::PhantomData, rc::Rc}; use crate::core::*; pub trait Atomic: 'static + Sized + Clone + Serializable { type ParseError: Error; fn deserialize(deserializer: &mut dyn Deserializer) -> Result; + fn unexpected_tail(tail: &[u8]) -> Self::ParseError; } pub struct AtomicFactory(PhantomData); @@ -45,7 +46,12 @@ impl<'a, Ctx: 'a + Context, A: Atomic> Factory<'a, Ctx> for AtomicFactory { fn deserialize( &self, deserializer: &mut dyn Deserializer, - ) -> Result { + _resolver: Rc>, + ) -> ParseResult<'a, Ctx, Self> { A::deserialize(deserializer) } + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { + A::unexpected_tail(tail) + } } diff --git a/src/std/cast.rs b/src/std/cast.rs new file mode 100644 index 0000000..70c26e0 --- /dev/null +++ b/src/std/cast.rs @@ -0,0 +1,61 @@ +use crate::core::*; +use crate::std::*; + +struct CastResolver<'a, Ctx: 'a + Context> { + points: Vec>>, +} + +impl<'a, Ctx: 'a + Context> Resolver<'a, Ctx> for CastResolver<'a, Ctx> +where + Ctx::LookupError: From>, +{ + fn resolve(self: Rc, address: Address) -> HashResolution<'a, Ctx> { + let point = &self + .points + .get(address.index) + .expect("CastResolved received an invalid address."); + if point.point != address.point { + panic!("CastResolved received an invalid address.") + } + Ctx::T::fmap( + |resolved| match resolved { + Ok(mentionable) => { + let mut vec = Vec::new(); + mentionable.serialize(&mut vec); + let resolver: Rc> = Rc::new(CastResolver { + points: mentionable.points(), + }); + Ok((vec, resolver)) + } + Err(error) => Err(match error { + ResolutionError::Lookup(lookup_error) => lookup_error, + ResolutionError::Parse(parse_error) => parse_error.into(), + }), + }, + point.resolve(), + ) + } +} + +pub type CastResult<'a, Ctx, A> = + Result>::Fctr as Factory<'a, Ctx>>::ParseError>; +impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx> +where + Ctx::LookupError: From>, +{ + /// . + /// + /// # Errors + /// + /// This function will return an error if . + pub fn cast>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { + let mut vec = Vec::new(); + self.serialize(&mut vec); + factory.parse_slice( + &vec, + Rc::new(CastResolver { + points: self.points(), + }), + ) + } +} diff --git a/src/std/nullable.rs b/src/std/nullable.rs new file mode 100644 index 0000000..e0bc57c --- /dev/null +++ b/src/std/nullable.rs @@ -0,0 +1,77 @@ +use crate::core::*; +use crate::std::*; + +enum Nullable<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + Null(A::Fctr), + NotNull(Point<'a, Ctx, A>), +} + +struct NullableFactory<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + factory: A::Fctr, +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for Nullable<'a, Ctx, A> { + fn serialize(&self, serializer: &mut dyn Serializer) { + serializer.write(match self { + Nullable::Null(_) => &HASH_ZEROS, + Nullable::NotNull(point) => &point.point, + }) + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Nullable<'a, Ctx, A> { + type Fctr = NullableFactory<'a, Ctx, A>; + + fn factory(&self) -> Self::Fctr { + match self { + Nullable::Null(factory) => NullableFactory { + factory: factory.clone(), + }, + Nullable::NotNull(point) => NullableFactory { + factory: point.origin.factory(), + }, + } + } + + fn points(&self) -> Vec>> { + match self { + Nullable::Null(_) => vec![], + Nullable::NotNull(point) => vec![point.typeless()], + } + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Clone for NullableFactory<'a, Ctx, A> { + fn clone(&self) -> Self { + Self { + factory: self.factory.clone(), + } + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> + for NullableFactory<'a, Ctx, A> +{ + type Mtbl = Nullable<'a, Ctx, A>; + + type ParseError = PointParseError; + + fn deserialize( + &self, + deserializer: &mut dyn Deserializer, + resolver: std::rc::Rc>, + ) -> ParseResult<'a, Ctx, Self> { + let point = deserializer.read_n_const::()?; + let factory = self.factory.clone(); + Ok(if point == HASH_ZEROS { + Nullable::Null(factory) + } else { + let mut addresses = Addresses::start(); + Nullable::NotNull(addresses.next_point(deserializer, resolver, factory)?) + }) + } + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { + PointParseError::WrongLength(HASH_SIZE + tail.len()) + } +}