diff --git a/src/core.rs b/src/core.rs index 9c0f872..9c2ce96 100644 --- a/src/core.rs +++ b/src/core.rs @@ -2,7 +2,7 @@ //! Brings [`Mentionable`]/[`Factory`]/[`Origin`] concepts from the original implementation in Python. //! Allows for more generic behaviour via [`Context`], as opposed to original async-only. -pub mod typeless; +mod typeless; pub use typeless::*; diff --git a/src/core/typeless.rs b/src/core/typeless.rs index 298e140..8367306 100644 --- a/src/core/typeless.rs +++ b/src/core/typeless.rs @@ -1,5 +1,3 @@ -//! Typeless. See [`Mentionable::points`]. - use super::*; type TypelessSerialize<'a> = dyn 'a + Fn(&mut dyn Serializer); diff --git a/src/std.rs b/src/std.rs index 9b2ac52..8821a3d 100644 --- a/src/std.rs +++ b/src/std.rs @@ -6,188 +6,14 @@ pub mod collections; pub mod inlining; mod local_origin; pub mod nullable; +pub mod point; +mod typeless; use std::{error::Error, fmt::Display, rc::Rc}; use crate::core::*; use crate::func::*; -struct WrappedOrigin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { - w_factory: A::Fctr, - w_resolve: Box Resolution<'a, Ctx, A>>, -} - -fn wrapped_origin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>( - factory: A::Fctr, - resolve: impl 'a + Fn() -> Resolution<'a, Ctx, A>, -) -> Rc> { - Rc::new(WrappedOrigin { - w_factory: factory, - w_resolve: Box::new(resolve), - }) -} - -trait MappableOrigin<'a, Ctx: 'a + Context>: Origin<'a, Ctx> { - fn map>( - self: Rc, - 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() -> 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| 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(), - ) -} - -impl<'a, Ctx: 'a + Context, O: ?Sized + Origin<'a, Ctx>> MappableOrigin<'a, Ctx> for O { - fn map>( - self: Rc, - 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(); - WrappedOrigin { - w_factory: map_factory(self.factory()), - w_resolve: Box::new(move || { - let origin = origin.clone(); - let map_ok = map_ok.clone(); - let map_err = map_err.clone(); - map_resolve(move || origin.clone().resolve(), map_ok, map_err) - }), - } - } -} - -impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for WrappedOrigin<'a, Ctx, A> { - type Mtbl = A; - - fn factory(&self) -> >::Fctr { - self.w_factory.clone() - } - - fn resolve(self: Rc) -> Resolution<'a, Ctx, A> { - (self.w_resolve)() - } -} - -impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { - /// Typeless version of the point. Useful for [Mentionable::points] implementaion. - pub fn typeless(&self) -> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> { - Point { - point: self.point, - origin: Rc::new(self.origin.clone().map( - TypelessMentionable::from_typed, - TypelessError::from_typed, - TypelessFactory::from_typed, - )), - } - } -} - -impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for Point<'a, Ctx, A> { - fn serialize(&self, serializer: &mut dyn Serializer) { - serializer.write(&self.point) - } -} - -impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Point<'a, Ctx, A> { - type Fctr = PointFactory; - - fn factory(&self) -> Self::Fctr { - PointFactory { - factory: self.origin.factory(), - } - } - - fn topology(&self) -> Hash { - Ctx::hash(&self.point) - } - - fn points(&self, points: &mut Vec>>) { - points.push(self.typeless()); - } -} - -#[derive(Clone)] -pub struct PointFactory { - factory: F, -} - -#[derive(Debug)] -pub enum PointParseError { - WrongLength(usize), -} - -impl Display for PointParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PointParseError::WrongLength(length) => f.write_fmt(format_args!( - "expected {} bytes, received {}.", - HASH_SIZE, length - )), - } - } -} - -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>> AsRef<[u8]> for Point<'a, Ctx, A> { - fn as_ref(&self) -> &[u8] { - &self.point - } -} - -impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFactory { - type Mtbl = Point<'a, Ctx, F::Mtbl>; - - type ParseError = PointParseError; - - fn deserialize( - &self, - deserializer: &mut dyn Deserializer, - resolver: Rc>, - addresses: &mut Addresses, - ) -> ParseResult<'a, Ctx, Self> { - Ok(addresses.next_point(deserializer, resolver, self.factory.clone())?) - } - - fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { - PointParseError::WrongLength(HASH_SIZE + tail.len()) - } -} - impl Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("{}@{}", hex::encode(self.point), self.index)) diff --git a/src/std/cast.rs b/src/std/cast.rs index a9045c0..8ada93b 100644 --- a/src/std/cast.rs +++ b/src/std/cast.rs @@ -3,6 +3,7 @@ //! //! p.s. the implementation is horrific. +use super::typeless::*; use crate::core::*; use crate::std::*; diff --git a/src/std/collections/stack.rs b/src/std/collections/stack.rs index ec22a8b..2c8cef7 100644 --- a/src/std/collections/stack.rs +++ b/src/std/collections/stack.rs @@ -3,6 +3,7 @@ use crate::core::*; use crate::std::inlining::*; use crate::std::nullable::*; +use crate::std::point::*; use crate::std::*; /// Node containing a (nullable) reference to the next node and an element. diff --git a/src/std/inlining.rs b/src/std/inlining.rs index 655918c..5c7bbcc 100644 --- a/src/std/inlining.rs +++ b/src/std/inlining.rs @@ -4,6 +4,7 @@ pub mod static_pair; use super::atomic::atomic_object::*; use super::atomic::*; +use super::point::*; use crate::core::*; use crate::std::*; diff --git a/src/std/local_origin.rs b/src/std/local_origin.rs index 5063184..9be8e4f 100644 --- a/src/std/local_origin.rs +++ b/src/std/local_origin.rs @@ -20,7 +20,7 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { fn from_mentionable(mentionable: A) -> Self { Self::from_values( - Ctx::hash(Self::prepare_bytes_for_hashing(&mentionable).as_slice()), + Ctx::hash(&Self::prepare_bytes_for_hashing(&mentionable)), LocalOrigin::from(mentionable), ) } diff --git a/src/std/nullable.rs b/src/std/nullable.rs index 7750484..c983480 100644 --- a/src/std/nullable.rs +++ b/src/std/nullable.rs @@ -1,6 +1,7 @@ //! This module introduces [`Option`]-like concepts into RADN typesystem using [`Nullable`]. use super::inlining::*; +use super::point::*; use crate::core::*; use crate::std::*; diff --git a/src/std/point.rs b/src/std/point.rs new file mode 100644 index 0000000..46685e2 --- /dev/null +++ b/src/std/point.rs @@ -0,0 +1,85 @@ +//! Module responsible for making [Point]s [Mentionable]. + +use std::error::Error; +use std::fmt::Display; +use std::rc::Rc; + +use crate::core::*; + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Serializable for Point<'a, Ctx, A> { + fn serialize(&self, serializer: &mut dyn Serializer) { + serializer.write(&self.point) + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Point<'a, Ctx, A> { + type Fctr = PointFactory; + + fn factory(&self) -> Self::Fctr { + PointFactory { + factory: self.origin.factory(), + } + } + + fn topology(&self) -> Hash { + Ctx::hash(&self.point) + } + + fn points(&self, points: &mut Vec>>) { + points.push(self.typeless()); + } +} + +#[derive(Clone)] +pub struct PointFactory { + factory: F, +} + +#[derive(Debug)] +pub enum PointParseError { + WrongLength(usize), +} + +impl Display for PointParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PointParseError::WrongLength(length) => f.write_fmt(format_args!( + "expected {} bytes, received {}.", + HASH_SIZE, length + )), + } + } +} + +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>> AsRef<[u8]> for Point<'a, Ctx, A> { + fn as_ref(&self) -> &[u8] { + &self.point + } +} + +impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFactory { + type Mtbl = Point<'a, Ctx, F::Mtbl>; + + type ParseError = PointParseError; + + fn deserialize( + &self, + deserializer: &mut dyn Deserializer, + resolver: Rc>, + addresses: &mut Addresses, + ) -> ParseResult<'a, Ctx, Self> { + Ok(addresses.next_point(deserializer, resolver, self.factory.clone())?) + } + + fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError { + PointParseError::WrongLength(HASH_SIZE + tail.len()) + } +} diff --git a/src/std/typeless.rs b/src/std/typeless.rs new file mode 100644 index 0000000..5a8067b --- /dev/null +++ b/src/std/typeless.rs @@ -0,0 +1,102 @@ +use std::rc::Rc; + +use crate::core::*; +use crate::func::*; + +struct WrappedOrigin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { + w_factory: A::Fctr, + w_resolve: Box Resolution<'a, Ctx, A>>, +} + +pub fn wrapped_origin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>( + factory: A::Fctr, + resolve: impl 'a + Fn() -> Resolution<'a, Ctx, A>, +) -> Rc> { + Rc::new(WrappedOrigin { + w_factory: factory, + w_resolve: Box::new(resolve), + }) +} + +trait MappableOrigin<'a, Ctx: 'a + Context>: Origin<'a, Ctx> { + fn map>( + self: Rc, + 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() -> 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| 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(), + ) +} + +impl<'a, Ctx: 'a + Context, O: ?Sized + Origin<'a, Ctx>> MappableOrigin<'a, Ctx> for O { + fn map>( + self: Rc, + 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(); + WrappedOrigin { + w_factory: map_factory(self.factory()), + w_resolve: Box::new(move || { + let origin = origin.clone(); + let map_ok = map_ok.clone(); + let map_err = map_err.clone(); + map_resolve(move || origin.clone().resolve(), map_ok, map_err) + }), + } + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Origin<'a, Ctx> for WrappedOrigin<'a, Ctx, A> { + type Mtbl = A; + + fn factory(&self) -> >::Fctr { + self.w_factory.clone() + } + + fn resolve(self: Rc) -> Resolution<'a, Ctx, A> { + (self.w_resolve)() + } +} + +impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { + /// Typeless version of the point. Useful for [Mentionable::points] implementaion. + pub fn typeless(&self) -> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> { + Point { + point: self.point, + origin: Rc::new(self.origin.clone().map( + TypelessMentionable::from_typed, + TypelessError::from_typed, + TypelessFactory::from_typed, + )), + } + } +}