Point::cast

This commit is contained in:
AF 2023-04-22 16:42:33 +00:00
parent eb153d6396
commit e40ea67e21
5 changed files with 82 additions and 4 deletions

View File

@ -15,6 +15,16 @@ struct WrappedOrigin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> {
w_resolve: Box<dyn 'a + Fn() -> 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<dyn Origin<'a, Ctx, Mtbl = A>> {
Rc::new(WrappedOrigin {
w_factory: factory,
w_resolve: Box::new(resolve),
})
}
trait MappableOrigin<'a, Ctx: 'a + Context>: Origin<'a, Ctx> {
fn map<B: Mentionable<'a, Ctx>>(
self: Rc<Self>,
@ -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<dyn Resolver<'a, Ctx>>) -> Self {
fn from_address(
address: Address,
factory: A::Fctr,
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> Self {
Point {
point: address.point,
origin: Rc::new(ResolverOrigin {
@ -191,7 +205,7 @@ impl Addresses {
resolver: Rc<dyn Resolver<'a, Ctx>>,
factory: A::Fctr,
) -> Result<Point<'a, Ctx, A>, &'b [u8]> {
Ok(Point::from_point(
Ok(Point::from_address(
self.next(deserializer)?,
factory,
resolver,

View File

@ -79,8 +79,11 @@ fn _parse_slice<A: Atomic>(slice: &[u8]) -> Result<A, A::ParseError> {
}
}
/// Extension trait to provide method-like utilities associated with [Atomic]s.
pub trait ExtAtomic: Atomic {
/// Short-hand for getting specific [`AtomicFactory`].
fn f() -> AtomicFactory<Self>;
/// Static equivalent of [`ExtFactory::parse_slice`].
fn parse_slice(slice: &[u8]) -> Result<Self, Self::ParseError>;
}

View File

@ -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<u8>,
}
/// 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<u8> {
self.data.clone()
}
}
#[cfg(test)]

View File

@ -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<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>,
}
/// 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<A, <<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError>;
impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx>
where
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<A: Mentionable<'a, Ctx>>(&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<CastError<'a>>,
{
/// See [`TypelessMentionable::cast`]
pub fn cast<A: Mentionable<'a, Ctx>>(&self, factory: A::Fctr) -> Point<'a, Ctx, A> {
let typeless_origin = self.origin.clone();
let origin: Rc<dyn Origin<Ctx, Mtbl = A>> = 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,
}
}
}

View File

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