extract resolution

This commit is contained in:
AF 2023-04-23 00:47:47 +00:00
parent 1b00d2c326
commit 7951425738
2 changed files with 161 additions and 156 deletions

View File

@ -3,11 +3,13 @@
//! Allows for more generic behaviour via [`Context`], as opposed to original async-only.
mod hashing;
mod resolution;
mod serialization;
mod slice_deserializer;
mod typeless;
pub use hashing::*;
pub use resolution::*;
pub use serialization::*;
pub use slice_deserializer::*;
pub use typeless::*;
@ -28,28 +30,9 @@ pub trait Context {
fn hash(s: &[u8]) -> Hash;
}
/// Failure yielded by [`Origin`].
#[derive(Debug)]
pub enum ResolutionError<L, P> {
Lookup(L),
Parse(P),
}
/// See [`ResolutionResult`].
pub type ResolutionFailure<'a, Ctx, A> = ResolutionError<
<Ctx as Context>::LookupError<'a>,
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
>;
/// Result yielded by [`Origin`].
pub type ResolutionResult<'a, Ctx, A> = Result<Rc<A>, ResolutionFailure<'a, Ctx, A>>;
/// Helper alias for [`WeakFunctor::F`] of [`Context::T`].
pub type Wrapped<'a, Ctx, A> = <<Ctx as Context>::T as WeakFunctor>::F<'a, A>;
/// Wrapped result returned by [`Origin`].
pub type Resolution<'a, Ctx, A> = Wrapped<'a, Ctx, ResolutionResult<'a, Ctx, A>>;
/// Fundamental trait for ADN objects.
pub trait Mentionable<'a, Ctx: 'a + Context>: 'a + Serializable {
/// Type of the associated factory.
@ -77,28 +60,6 @@ pub trait Mentionable<'a, Ctx: 'a + Context>: 'a + Serializable {
}
}
/// Short-hand for the type of values returned by [`Resolver::resolve`].
pub type HashResolution<'a, Ctx> = Wrapped<
'a,
Ctx,
Result<(Vec<u8>, Rc<dyn Resolver<'a, Ctx>>), <Ctx as Context>::LookupError<'a>>,
>;
/// Value accepted by [`Resolver::resolve`]. Includes index to make it order-sensitive.
#[derive(Clone, Copy, Debug)]
pub struct Address {
pub point: Hash,
/// Index of the point in the [`Mentionable::points()`].
pub index: usize,
}
/// Trait representing the "rainbow table" behaviour.
pub trait Resolver<'a, Ctx: 'a + Context>: 'a {
/// Successfully returned value should be the inverse of the point passed
/// with topology header ([`Mentionable::topology()`]) omitted.
fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, Ctx>;
}
/// Short-hand for the type of vaalues returned by [`Factory::deserialize`].
pub type ParseResult<'a, Ctx, F> =
Result<<F as Factory<'a, Ctx>>::Mtbl, <F as Factory<'a, Ctx>>::ParseError>;
@ -152,111 +113,6 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> {
pub fn resolve(&self) -> Resolution<'a, Ctx, A> {
self.origin.clone().resolve()
}
/// Make a [Point] from an [Address].
pub fn from_address(
address: Address,
factory: A::Fctr,
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> Self {
Point {
point: address.point,
origin: Rc::new(ResolverOrigin {
r_factory: factory,
r_address: address,
r_resolver: resolver,
}),
}
}
}
/// Preferred way to parse [Point]s off of a [Serializer].
pub struct Addresses {
current: usize,
}
impl Addresses {
/// Read the next [Address].
pub fn next<'a>(
&mut self,
deserializer: &'a mut dyn Deserializer,
) -> Result<Address, &'a [u8]> {
let point = deserializer.read_n_const::<HASH_SIZE>()?;
let address = Address {
point,
index: self.current,
};
self.current += 1;
Ok(address)
}
/// Read the next [Point].
pub fn next_point<'a, 'b, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
&mut self,
deserializer: &'b mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>,
factory: A::Fctr,
) -> Result<Point<'a, Ctx, A>, &'b [u8]> {
Ok(Point::from_address(
self.next(deserializer)?,
factory,
resolver,
))
}
/// Start reading the [Address]es.
fn start() -> Self {
Addresses { current: 0 }
}
}
struct ResolverOrigin<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> {
r_factory: F,
r_address: Address,
r_resolver: Rc<dyn Resolver<'a, Ctx>>,
}
fn _resolve_origin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
origin: Rc<ResolverOrigin<'a, Ctx, A::Fctr>>,
) -> 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) -> <Self::Mtbl as Mentionable<'a, Ctx>>::Fctr {
self.r_factory.clone()
}
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl> {
_resolve_origin(self)
}
}
fn _parse_slice<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
factory: &A::Fctr,
slice: &[u8],
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> ParseResult<'a, Ctx, A::Fctr> {
let mut deserializer = SliceDeserializer::from(slice);
let mentionable = factory.deserialize(&mut deserializer, resolver, &mut Addresses::start())?;
let tail = deserializer.read_all();
if tail.is_empty() {
Ok(mentionable)
} else {
Err(factory.unexpected_tail(tail))
}
}
/// Extension trait for factories.
@ -268,13 +124,3 @@ pub trait ExtFactory<'a, Ctx: 'a + Context>: Factory<'a, Ctx> {
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> 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<dyn Resolver<'a, Ctx>>,
) -> ParseResult<'a, Ctx, Self> {
_parse_slice::<Ctx, F::Mtbl>(self, slice, resolver)
}
}

159
src/core/resolution.rs Normal file
View File

@ -0,0 +1,159 @@
use super::*;
/// Failure yielded by [`Origin`].
#[derive(Debug)]
pub enum ResolutionError<L, P> {
Lookup(L),
Parse(P),
}
/// See [`ResolutionResult`].
pub type ResolutionFailure<'a, Ctx, A> = ResolutionError<
<Ctx as Context>::LookupError<'a>,
<<A as Mentionable<'a, Ctx>>::Fctr as Factory<'a, Ctx>>::ParseError,
>;
/// Result yielded by [`Origin`].
pub type ResolutionResult<'a, Ctx, A> = Result<Rc<A>, ResolutionFailure<'a, Ctx, A>>;
/// Wrapped result returned by [`Origin`].
pub type Resolution<'a, Ctx, A> = Wrapped<'a, Ctx, ResolutionResult<'a, Ctx, A>>;
/// Short-hand for the type of values returned by [`Resolver::resolve`].
pub type HashResolution<'a, Ctx> = Wrapped<
'a,
Ctx,
Result<(Vec<u8>, Rc<dyn Resolver<'a, Ctx>>), <Ctx as Context>::LookupError<'a>>,
>;
/// Value accepted by [`Resolver::resolve`]. Includes index to make it order-sensitive.
#[derive(Clone, Copy, Debug)]
pub struct Address {
pub point: Hash,
/// Index of the point in the [`Mentionable::points()`].
pub index: usize,
}
/// Trait representing the "rainbow table" behaviour.
pub trait Resolver<'a, Ctx: 'a + Context>: 'a {
/// Successfully returned value should be the inverse of the point passed
/// with topology header ([`Mentionable::topology()`]) omitted.
fn resolve(self: Rc<Self>, address: Address) -> HashResolution<'a, Ctx>;
}
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> {
/// Make a [Point] from an [Address].
pub fn from_address(
address: Address,
factory: A::Fctr,
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> Self {
Point {
point: address.point,
origin: Rc::new(ResolverOrigin {
r_factory: factory,
r_address: address,
r_resolver: resolver,
}),
}
}
}
/// Preferred way to parse [Point]s off of a [Serializer].
pub struct Addresses {
current: usize,
}
impl Addresses {
/// Read the next [Address].
pub fn next<'a>(
&mut self,
deserializer: &'a mut dyn Deserializer,
) -> Result<Address, &'a [u8]> {
let point = deserializer.read_n_const::<HASH_SIZE>()?;
let address = Address {
point,
index: self.current,
};
self.current += 1;
Ok(address)
}
/// Read the next [Point].
pub fn next_point<'a, 'b, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
&mut self,
deserializer: &'b mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>,
factory: A::Fctr,
) -> Result<Point<'a, Ctx, A>, &'b [u8]> {
Ok(Point::from_address(
self.next(deserializer)?,
factory,
resolver,
))
}
/// Start reading the [Address]es.
fn start() -> Self {
Addresses { current: 0 }
}
}
struct ResolverOrigin<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> {
r_factory: F,
r_address: Address,
r_resolver: Rc<dyn Resolver<'a, Ctx>>,
}
fn _resolve_origin<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
origin: Rc<ResolverOrigin<'a, Ctx, A::Fctr>>,
) -> 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) -> <Self::Mtbl as Mentionable<'a, Ctx>>::Fctr {
self.r_factory.clone()
}
fn resolve(self: Rc<Self>) -> Resolution<'a, Ctx, Self::Mtbl> {
_resolve_origin(self)
}
}
fn _parse_slice<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>>(
factory: &A::Fctr,
slice: &[u8],
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> ParseResult<'a, Ctx, A::Fctr> {
let mut deserializer = SliceDeserializer::from(slice);
let mentionable = factory.deserialize(&mut deserializer, resolver, &mut Addresses::start())?;
let tail = deserializer.read_all();
if tail.is_empty() {
Ok(mentionable)
} else {
Err(factory.unexpected_tail(tail))
}
}
impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> ExtFactory<'a, Ctx> for F {
fn parse_slice(
&self,
slice: &[u8],
resolver: Rc<dyn Resolver<'a, Ctx>>,
) -> ParseResult<'a, Ctx, Self> {
_parse_slice::<Ctx, F::Mtbl>(self, slice, resolver)
}
}