From e40ea67e21c5bd1cb724d5dc783f992d55766e55 Mon Sep 17 00:00:00 2001 From: timofey Date: Sat, 22 Apr 2023 16:42:33 +0000 Subject: [PATCH] Point::cast --- src/std.rs | 18 +++++++++++++-- src/std/atomic.rs | 3 +++ src/std/atomic/plain.rs | 14 +++++++++++- src/std/cast.rs | 49 +++++++++++++++++++++++++++++++++++++++++ src/std/nullable.rs | 2 +- 5 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/std.rs b/src/std.rs index 37575a4..811190a 100644 --- a/src/std.rs +++ b/src/std.rs @@ -15,6 +15,16 @@ struct WrappedOrigin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> { 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, @@ -152,7 +162,11 @@ impl From<&[u8]> for PointParseError { } impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> { - fn from_point(address: Address, factory: A::Fctr, resolver: Rc>) -> Self { + fn from_address( + address: Address, + factory: A::Fctr, + resolver: Rc>, + ) -> Self { Point { point: address.point, origin: Rc::new(ResolverOrigin { @@ -191,7 +205,7 @@ impl Addresses { resolver: Rc>, factory: A::Fctr, ) -> Result, &'b [u8]> { - Ok(Point::from_point( + Ok(Point::from_address( self.next(deserializer)?, factory, resolver, diff --git a/src/std/atomic.rs b/src/std/atomic.rs index cee41cf..cc6354d 100644 --- a/src/std/atomic.rs +++ b/src/std/atomic.rs @@ -79,8 +79,11 @@ fn _parse_slice(slice: &[u8]) -> Result { } } +/// Extension trait to provide method-like utilities associated with [Atomic]s. pub trait ExtAtomic: Atomic { + /// Short-hand for getting specific [`AtomicFactory`]. fn f() -> AtomicFactory; + /// Static equivalent of [`ExtFactory::parse_slice`]. fn parse_slice(slice: &[u8]) -> Result; } diff --git a/src/std/atomic/plain.rs b/src/std/atomic/plain.rs index c424324..0a1aea3 100644 --- a/src/std/atomic/plain.rs +++ b/src/std/atomic/plain.rs @@ -1,12 +1,18 @@ +//! [`Plain`] type for storing raw byte sequnces. + use std::fmt::Display; use crate::std::atomic::*; -#[derive(Clone)] +/// Raw bytes storage. Use [`Plain::raw`] to get the data. +/// +/// Note: this type uses [`Deserializer::read_all`] for parsing. +#[derive(Clone, Debug)] pub struct Plain { data: Vec, } +/// This shouldn't happen given [`Deserializer::read_all`] being used for parsing. #[derive(Debug)] pub enum PlainParseError {} @@ -40,9 +46,15 @@ impl Atomic for Plain { } impl Plain { + /// Copy bytes into a new instance. pub fn from_slice(slice: &[u8]) -> Self { Plain { data: slice.into() } } + + /// Copy of bytes stored inside. + pub fn raw(&self) -> Vec { + self.data.clone() + } } #[cfg(test)] diff --git a/src/std/cast.rs b/src/std/cast.rs index b9b7bcb..a255cde 100644 --- a/src/std/cast.rs +++ b/src/std/cast.rs @@ -1,3 +1,8 @@ +//! Utilities to convert from typeless instances defined in [`crate::core`]. +//! See [`TypelessMentionable::cast`]/[`Point::cast`]. +//! +//! p.s. the implementation is horrific. + use crate::core::*; use crate::std::*; @@ -5,13 +10,22 @@ struct CastResolver<'a, Ctx: 'a + Context> { points: Vec>>, } +/// Used to represent errors that might arise during resolution/parsion. +/// Is expected to be classified as [`Context::LookupError`] rather than [`Factory::ParseError`]. +/// [`CastError::AddressIndexOutOfBounds`] and [`CastError::AddressPointMismatch`] +/// variants generally shouldn't happen. #[derive(Debug)] pub enum CastError<'a> { Typeless(TypelessError<'a>), + /// If you don't know what that means, it's a good idea to [`panic!`]. + /// Happens due to internal resolver using indices rather than `point`s. + /// This error usually indicates inconsistent behaviour + /// of [`Mentionable::points`] and/or [`Mentionable::topology`]. AddressIndexOutOfBounds { index: usize, length: usize, }, + /// See [`CastError::AddressIndexOutOfBounds`]. AddressPointMismatch { expected: Hash, received: Hash, @@ -84,12 +98,15 @@ where } } +/// Returned by [`TypelessMentionable::cast`]. pub type CastResult<'a, Ctx, A> = Result>::Fctr as Factory<'a, Ctx>>::ParseError>; + 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> { factory.parse_slice( &self.bytes(), @@ -99,3 +116,35 @@ where ) } } + +impl<'a, Ctx: Context> Point<'a, Ctx, TypelessMentionable<'a, Ctx>> +where + Ctx::LookupError<'a>: From>, +{ + /// See [`TypelessMentionable::cast`] + pub fn cast>(&self, factory: A::Fctr) -> Point<'a, Ctx, A> { + let typeless_origin = self.origin.clone(); + let origin: Rc> = wrapped_origin(factory.clone(), move || { + let factory = factory.clone(); + Ctx::T::fmap( + move |resolved| match resolved { + Ok(typeless_mentionable) => match typeless_mentionable.cast(factory) { + Ok(mentionable) => Ok(Rc::new(mentionable)), + Err(parse_error) => Err(ResolutionError::Parse(parse_error)), + }, + Err(error) => Err(ResolutionError::Lookup(match error { + ResolutionError::Lookup(lookup_error) => lookup_error, + ResolutionError::Parse(parse_error) => { + CastError::Typeless(parse_error).into() + } + })), + }, + typeless_origin.clone().resolve(), + ) + }); + Point { + point: self.point, + origin, + } + } +} diff --git a/src/std/nullable.rs b/src/std/nullable.rs index e5cbbbc..932d558 100644 --- a/src/std/nullable.rs +++ b/src/std/nullable.rs @@ -71,7 +71,7 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx> Ok(if address.point == HASH_ZEROS { Nullable::Null(factory) } else { - Nullable::NotNull(Point::from_point(address, factory, resolver)) + Nullable::NotNull(Point::from_address(address, factory, resolver)) }) }