addresses moved to core

This commit is contained in:
AF 2023-04-22 23:22:54 +00:00
parent 8ebe30cd65
commit 29d0eb3ee2
8 changed files with 276 additions and 196 deletions

View File

@ -2,7 +2,7 @@
//! Brings [`Mentionable`]/[`Factory`]/[`Origin`] concepts from the original implementation in Python. //! Brings [`Mentionable`]/[`Factory`]/[`Origin`] concepts from the original implementation in Python.
//! Allows for more generic behaviour via [`Context`], as opposed to original async-only. //! Allows for more generic behaviour via [`Context`], as opposed to original async-only.
use std::{error::Error, fmt::Display, rc::Rc}; use std::{cmp::min, error::Error, fmt::Display, rc::Rc};
use crate::func::*; use crate::func::*;
@ -155,6 +155,7 @@ pub trait Factory<'a, Ctx: 'a + Context>: Clone + 'a {
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self>; ) -> ParseResult<'a, Ctx, Self>;
/// Called by finite stream parsers if there's any data left. /// Called by finite stream parsers if there's any data left.
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError; fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError;
@ -231,6 +232,22 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> {
LocalOrigin::from(mentionable), LocalOrigin::from(mentionable),
) )
} }
/// 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,
}),
}
}
} }
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> From<A> for Point<'a, Ctx, A> { impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> From<A> for Point<'a, Ctx, A> {
@ -251,8 +268,8 @@ pub struct TypelessMentionable<'a, Ctx: 'a + Context> {
type TypelessParsed<'a, Ctx> = Result<TypelessMentionable<'a, Ctx>, Box<dyn 'a + Error>>; type TypelessParsed<'a, Ctx> = Result<TypelessMentionable<'a, Ctx>, Box<dyn 'a + Error>>;
type TypelessDeserialize<'a, Ctx> = type TypelessDeserialize<'a, Ctx> = dyn 'a
dyn 'a + Fn(&mut dyn Deserializer, Rc<dyn Resolver<'a, Ctx>>) -> TypelessParsed<'a, Ctx>; + Fn(&mut dyn Deserializer, Rc<dyn Resolver<'a, Ctx>>, &mut Addresses) -> TypelessParsed<'a, Ctx>;
type TypelessUnexpectedTail<'a> = dyn 'a + Fn(&[u8]) -> TypelessError<'a>; type TypelessUnexpectedTail<'a> = dyn 'a + Fn(&[u8]) -> TypelessError<'a>;
@ -318,8 +335,9 @@ impl<'a, Ctx: 'a + Context> Factory<'a, Ctx> for TypelessFactory<'a, Ctx> {
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
match (self.t_deserialize)(deserializer, resolver) { match (self.t_deserialize)(deserializer, resolver, addresses) {
Ok(mentionable) => Ok(mentionable), Ok(mentionable) => Ok(mentionable),
Err(error) => Err(TypelessError(error)), Err(error) => Err(TypelessError(error)),
} }
@ -348,8 +366,8 @@ impl<'a, Ctx: 'a + Context> TypelessFactory<'a, Ctx> {
pub fn from_typed<F: Factory<'a, Ctx>>(factory: F) -> Self { pub fn from_typed<F: Factory<'a, Ctx>>(factory: F) -> Self {
let tail_factory = factory.clone(); let tail_factory = factory.clone();
TypelessFactory { TypelessFactory {
t_deserialize: Rc::new(move |deserializer, resolver| { t_deserialize: Rc::new(move |deserializer, resolver, addresses| {
match factory.deserialize(deserializer, resolver) { match factory.deserialize(deserializer, resolver, addresses) {
Ok(mentionable) => Ok(TypelessMentionable::from_typed(Rc::new(mentionable))), Ok(mentionable) => Ok(TypelessMentionable::from_typed(Rc::new(mentionable))),
Err(error) => Err(Box::new(error)), Err(error) => Err(Box::new(error)),
} }
@ -366,3 +384,158 @@ impl<'a> TypelessError<'a> {
TypelessError(Box::new(error)) TypelessError(Box::new(error))
} }
} }
/// 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 }
}
}
pub trait ExtDeserializer {
fn read_n_const<const N: usize>(&mut self) -> Result<[u8; N], &[u8]>;
}
impl<D: ?Sized + Deserializer> ExtDeserializer for D {
fn read_n_const<const N: usize>(&mut self) -> Result<[u8; N], &[u8]> {
let slice = self.read_n(N);
match slice.try_into() {
Ok(array) => Ok(array),
Err(_) => Err(slice),
}
}
}
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))
}
}
pub trait ExtFactory<'a, Ctx: 'a + Context>: Factory<'a, Ctx> {
fn parse_slice(
&self,
slice: &[u8],
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)
}
}
pub 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
}
}

View File

@ -1,10 +1,11 @@
//! Standard extensions to [`crate::core`].
pub mod atomic; pub mod atomic;
pub mod cast; pub mod cast;
pub mod collections; pub mod collections;
pub mod inlining; pub mod inlining;
pub mod nullable; pub mod nullable;
use std::cmp::min;
use std::{error::Error, fmt::Display, rc::Rc}; use std::{error::Error, fmt::Display, rc::Rc};
use crate::core::*; use crate::core::*;
@ -161,62 +162,12 @@ impl From<&[u8]> for PointParseError {
} }
} }
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Point<'a, Ctx, A> {
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,
}),
}
}
}
impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> AsRef<[u8]> for Point<'a, Ctx, A> { impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> AsRef<[u8]> for Point<'a, Ctx, A> {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
&self.point &self.point
} }
} }
pub struct Addresses {
current: usize,
}
impl Addresses {
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)
}
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,
))
}
fn start() -> Self {
Addresses { current: 0 }
}
}
impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFactory<F> { impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFactory<F> {
type Mtbl = Point<'a, Ctx, F::Mtbl>; type Mtbl = Point<'a, Ctx, F::Mtbl>;
@ -226,8 +177,8 @@ impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFacto
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
let mut addresses = Addresses::start();
Ok(addresses.next_point(deserializer, resolver, self.factory.clone())?) Ok(addresses.next_point(deserializer, resolver, self.factory.clone())?)
} }
@ -236,121 +187,6 @@ impl<'a, Ctx: 'a + Context, F: Factory<'a, Ctx>> Factory<'a, Ctx> for PointFacto
} }
} }
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)
}
}
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<dyn Resolver<'a, Ctx>>,
) -> 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<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)
}
}
pub trait ExtDeserializer {
fn read_n_const<const N: usize>(&mut self) -> Result<[u8; N], &[u8]>;
}
impl<D: ?Sized + Deserializer> ExtDeserializer for D {
fn read_n_const<const N: usize>(&mut self) -> Result<[u8; N], &[u8]> {
let slice = self.read_n(N);
match slice.try_into() {
Ok(array) => Ok(array),
Err(_) => Err(slice),
}
}
}
impl Display for Address { impl Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}@{}", hex::encode(self.point), self.index)) f.write_fmt(format_args!("{}@{}", hex::encode(self.point), self.index))

View File

@ -1,7 +1,10 @@
//! Provides [Atomic]-[Mentionable] interface.
use std::ops::Deref; use std::ops::Deref;
use super::*; use super::*;
/// Generic implementation of a [Mentionable] for [Atomic]s.
pub struct AtomicObject<A: Atomic> { pub struct AtomicObject<A: Atomic> {
atomic: A, atomic: A,
} }
@ -46,12 +49,14 @@ impl<'a, Ctx: 'a + Context, A: Atomic> Mentionable<'a, Ctx> for AtomicObject<A>
fn points(&self, _points: &mut Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>) {} fn points(&self, _points: &mut Vec<Point<'a, Ctx, TypelessMentionable<'a, Ctx>>>) {}
} }
/// Generic implementation of a factory for [Atomic]s. /// Generic implementation of a [Factory] for [Atomic]s.
pub struct AtomicFactory<A: Atomic>(PhantomData<A>); pub struct AtomicFactory<A: Atomic> {
_pd: PhantomData<A>,
}
impl<A: Atomic> AtomicFactory<A> { impl<A: Atomic> AtomicFactory<A> {
fn new() -> Self { fn new() -> Self {
AtomicFactory(PhantomData) AtomicFactory { _pd: PhantomData }
} }
} }
@ -70,6 +75,7 @@ impl<'a, Ctx: 'a + Context, A: Atomic> Factory<'a, Ctx> for AtomicFactory<A> {
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
_resolver: Rc<dyn Resolver<'a, Ctx>>, _resolver: Rc<dyn Resolver<'a, Ctx>>,
_addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
Ok(A::deserialize(deserializer)?.into()) Ok(A::deserialize(deserializer)?.into())
} }

View File

@ -1,3 +1,5 @@
//! [`Pair`] implementation based on [`StaticPair`].
use std::error::Error; use std::error::Error;
use std::fmt::Display; use std::fmt::Display;
@ -18,7 +20,7 @@ impl<A: Serializable, B: Serializable> StaticPairSerializable for Pair<A, B> {
type SA = A; type SA = A;
type SB = B; type SB = B;
fn s_elements(&self) -> (&Self::SA, &Self::SB) { fn elements(&self) -> (&Self::SA, &Self::SB) {
(&self.a, &self.b) (&self.a, &self.b)
} }
} }
@ -89,8 +91,4 @@ where
b: self.b.factory(), b: self.b.factory(),
} }
} }
fn elements(&self) -> (&Self::A, &Self::B) {
(&self.a, &self.b)
}
} }

View File

@ -88,16 +88,23 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
let rest = let rest = match NullableFactory::new(self.clone()).deserialize(
match NullableFactory::new(self.clone()).deserialize(deserializer, resolver.clone()) { deserializer,
resolver.clone(),
addresses,
) {
Ok(rest) => rest, Ok(rest) => rest,
Err(ppe) => { Err(ppe) => {
return Err(StackParseError::Point(ppe)); return Err(StackParseError::Point(ppe));
} }
}; };
let element = Rc::new( let element = Rc::new(
match self.element_factory.deserialize(deserializer, resolver) { match self
.element_factory
.deserialize(deserializer, resolver, addresses)
{
Ok(element) => element, Ok(element) => element,
Err(epe) => { Err(epe) => {
return Err(StackParseError::Element(epe)); return Err(StackParseError::Element(epe));

View File

@ -1,3 +1,5 @@
//! Traits to better express parsing semantics.
pub mod static_pair; pub mod static_pair;
use super::atomic::atomic_object::*; use super::atomic::atomic_object::*;
@ -5,28 +7,44 @@ use super::atomic::*;
use crate::core::*; use crate::core::*;
use crate::std::*; use crate::std::*;
/// This factory should return an error on EOF.
pub trait InlineableFactory {} pub trait InlineableFactory {}
/// This factory always reads the same amount of bytes or returns error.
pub trait FixedSizeFactory: InlineableFactory { pub trait FixedSizeFactory: InlineableFactory {
/// For [`ConstSizeFactory`] this must return [`ConstSizeFactory::SIZE`].
fn size(&self) -> usize; fn size(&self) -> usize;
} }
/// Compile-time analogue of [`FixedSizeFactory`].
pub trait ConstSizeFactory: FixedSizeFactory { pub trait ConstSizeFactory: FixedSizeFactory {
/// Must be equal to [`FixedSizeFactory::size()`].
const SIZE: usize; const SIZE: usize;
} }
/// Object analogue of [`InlineableFactory`].
pub trait InlineableObject<'a, Ctx: 'a + Context>: 'a {} pub trait InlineableObject<'a, Ctx: 'a + Context>: 'a {}
/// Object analogue of [`FixedSizeFactory`].
pub trait FixedSizeObject<'a, Ctx: 'a + Context>: InlineableObject<'a, Ctx> { pub trait FixedSizeObject<'a, Ctx: 'a + Context>: InlineableObject<'a, Ctx> {
/// For [`ConstSizeObject`] this must return [`ConstSizeObject::SIZE`].
fn size(&self) -> usize; fn size(&self) -> usize;
} }
/// Object analogue of [`ConstSizeFactory`].
pub trait ConstSizeObject<'a, Ctx: 'a + Context>: FixedSizeObject<'a, Ctx> { pub trait ConstSizeObject<'a, Ctx: 'a + Context>: FixedSizeObject<'a, Ctx> {
/// Must be equal to [`FixedSizeObject::size()`].
const SIZE: usize; const SIZE: usize;
} }
/// Atomic analogue of [`InlineableFactory`]/[`InlineableObject`].
pub trait InlineableAtomic {} pub trait InlineableAtomic {}
/// Atomic analogue of [`ConstSizeFactory`]/[`ConstSizeObject`].
///
/// Note: `FixedSizeAtomic` doesn't exist because it would
/// either be const anyway
/// or have a very undesireable implementation.
pub trait ConstSizeAtomic: InlineableAtomic { pub trait ConstSizeAtomic: InlineableAtomic {
const SIZE: usize; const SIZE: usize;
} }
@ -64,6 +82,7 @@ where
const SIZE: usize = A::Fctr::SIZE; const SIZE: usize = A::Fctr::SIZE;
} }
/// Error returned by [`CheckedParse::deserialize_checked`]/[`CheckedSerialize::serialize_checked`].
#[derive(Debug)] #[derive(Debug)]
pub struct SizeError { pub struct SizeError {
expected: usize, expected: usize,
@ -81,6 +100,7 @@ impl Display for SizeError {
impl Error for SizeError {} impl Error for SizeError {}
/// Wrapper for [`SizeError`]/[`Factory::ParseError`].
#[derive(Debug)] #[derive(Debug)]
pub enum CheckedParseError<P: Error> { pub enum CheckedParseError<P: Error> {
Parse(P), Parse(P),
@ -104,18 +124,24 @@ impl<P: Error> From<P> for CheckedParseError<P> {
} }
} }
/// Returned by [`CheckedParse::deserialize_checked`].
pub type CheckedParseResult<'a, Ctx, F> = pub type CheckedParseResult<'a, Ctx, F> =
Result<<F as Factory<'a, Ctx>>::Mtbl, CheckedParseError<<F as Factory<'a, Ctx>>::ParseError>>; Result<<F as Factory<'a, Ctx>>::Mtbl, CheckedParseError<<F as Factory<'a, Ctx>>::ParseError>>;
/// Extension trait for factories that ensures fixed size read.
pub trait CheckedParse<'a, Ctx: 'a + Context>: FixedSizeFactory + Factory<'a, Ctx> { pub trait CheckedParse<'a, Ctx: 'a + Context>: FixedSizeFactory + Factory<'a, Ctx> {
/// Verify proper read length using [`Deserializer::tell`].
fn deserialize_checked( fn deserialize_checked(
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> CheckedParseResult<'a, Ctx, Self>; ) -> CheckedParseResult<'a, Ctx, Self>;
} }
/// Extension trait for factories that ensures fixed size write.
pub trait CheckedSerialize<'a, Ctx: 'a + Context>: Serializable + FixedSizeObject<'a, Ctx> { pub trait CheckedSerialize<'a, Ctx: 'a + Context>: Serializable + FixedSizeObject<'a, Ctx> {
/// Verify proper write length using [`Serializer::tell`].
fn serialize_checked(&self, serializer: &mut dyn Serializer) -> Result<(), SizeError>; fn serialize_checked(&self, serializer: &mut dyn Serializer) -> Result<(), SizeError>;
} }
@ -124,10 +150,11 @@ impl<'a, Ctx: 'a + Context, F: FixedSizeFactory + Factory<'a, Ctx>> CheckedParse
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> CheckedParseResult<'a, Ctx, Self> { ) -> CheckedParseResult<'a, Ctx, Self> {
let expected_size = self.size(); let expected_size = self.size();
let start = deserializer.tell(); let start = deserializer.tell();
let result = self.deserialize(deserializer, resolver)?; let result = self.deserialize(deserializer, resolver, addresses)?;
let end = deserializer.tell(); let end = deserializer.tell();
let received_size = end - start; let received_size = end - start;
if received_size == expected_size { if received_size == expected_size {
@ -161,6 +188,9 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx> + FixedSizeObject<'a, Ctx>>
} }
} }
/// Trait useful for objects which aren't influenced by
/// whether some other type (for example, a generic parameter type)
/// is fixed-size or not.
pub trait AlwaysFixedSize { pub trait AlwaysFixedSize {
fn _size(&self) -> usize; fn _size(&self) -> usize;
} }
@ -173,6 +203,7 @@ impl<F: AlwaysFixedSize> FixedSizeFactory for F {
} }
} }
/// Compile-time analogue of [`AlwaysFixedSize`].
pub trait AlwaysConstSize { pub trait AlwaysConstSize {
const _SIZE: usize; const _SIZE: usize;
} }

View File

@ -1,39 +1,66 @@
//! Generic implementation for objects that are structured
//! like a pair of two other objects.
use std::ops::Deref; use std::ops::Deref;
use super::*; use super::*;
use crate::core::*; use crate::core::*;
/// Trait to represent serialisation of object's data.
/// Due to serialisation being [Context]-free in RADN,
/// this functionality is in a separate trait.
pub trait StaticPairSerializable { pub trait StaticPairSerializable {
/// First element's type. Must equal [`StaticPair::A`].
type SA: Serializable; type SA: Serializable;
/// Second element's type. Must equal [`StaticPair::B`].
type SB: Serializable; type SB: Serializable;
fn s_elements(&self) -> (&Self::SA, &Self::SB); /// Borrow both elements.
fn elements(&self) -> (&Self::SA, &Self::SB);
} }
/// Trait to be implemented on object data.
///
/// [`StaticPair::FA`]/[`StaticPair::FB`] are required members
/// for clarity and [`StaticPair`]'s simpler implementation
/// at the cost of having to specify two extra fields.
///
/// Note: [`StaticPair::FA`] requires [`InlineableFactory`] be implemented.
pub trait StaticPair<'a, Ctx: 'a + Context>: pub trait StaticPair<'a, Ctx: 'a + Context>:
'a + StaticPairSerializable<SA = Self::A, SB = Self::B> 'a + StaticPairSerializable<SA = Self::A, SB = Self::B>
{ {
/// [Factory] data. May, depending on the usecase, include factory (factories) on the element(s).
type FactoryData: 'a + Clone; type FactoryData: 'a + Clone;
/// First element's type. Must equal [`StaticPairSerializable::SA`].
type A: Mentionable<'a, Ctx, Fctr = Self::FA>; type A: Mentionable<'a, Ctx, Fctr = Self::FA>;
/// Second element's type. Must equal [`StaticPairSerializable::SB`].
type B: Mentionable<'a, Ctx, Fctr = Self::FB>; type B: Mentionable<'a, Ctx, Fctr = Self::FB>;
/// First element's factory.
type FA: Factory<'a, Ctx, Mtbl = Self::A> + InlineableFactory; type FA: Factory<'a, Ctx, Mtbl = Self::A> + InlineableFactory;
/// Second element's factory.
type FB: Factory<'a, Ctx, Mtbl = Self::B>; type FB: Factory<'a, Ctx, Mtbl = Self::B>;
/// See [Factory::ParseError].
type ParseError: 'a + Error; type ParseError: 'a + Error;
/// Borrow both elements' factories.
fn factories(factory_data: &Self::FactoryData) -> (&Self::FA, &Self::FB); fn factories(factory_data: &Self::FactoryData) -> (&Self::FA, &Self::FB);
/// Construct the object from the elements.
fn from_parsed(factory_data: &Self::FactoryData, a: Self::A, b: Self::B) -> Self; fn from_parsed(factory_data: &Self::FactoryData, a: Self::A, b: Self::B) -> Self;
/// Regularise the error returned while parsing the first element.
fn from_error_a( fn from_error_a(
factory_data: &Self::FactoryData, factory_data: &Self::FactoryData,
error: <Self::FA as Factory<'a, Ctx>>::ParseError, error: <Self::FA as Factory<'a, Ctx>>::ParseError,
) -> Self::ParseError; ) -> Self::ParseError;
/// Regularise the error returned while parsing the second element.
fn from_error_b( fn from_error_b(
factory_data: &Self::FactoryData, factory_data: &Self::FactoryData,
error: <Self::FB as Factory<'a, Ctx>>::ParseError, error: <Self::FB as Factory<'a, Ctx>>::ParseError,
) -> Self::ParseError; ) -> Self::ParseError;
/// Derive factory data from the object data.
fn factory_data(&self) -> Self::FactoryData; fn factory_data(&self) -> Self::FactoryData;
fn elements(&self) -> (&Self::A, &Self::B);
} }
/// Generic implementation of a [Mentionable] for [StaticPair]s.
pub struct StaticPairObject<SP> { pub struct StaticPairObject<SP> {
pair: SP, pair: SP,
} }
@ -58,13 +85,14 @@ impl<SP> Deref for StaticPairObject<SP> {
} }
} }
/// Generic implementation of a [Factory] for [StaticPair]s.
pub struct StaticPairFactory<'a, Ctx: 'a + Context, SP: StaticPair<'a, Ctx>> { pub struct StaticPairFactory<'a, Ctx: 'a + Context, SP: StaticPair<'a, Ctx>> {
factory_data: SP::FactoryData, factory_data: SP::FactoryData,
} }
impl<SP: StaticPairSerializable> Serializable for StaticPairObject<SP> { impl<SP: StaticPairSerializable> Serializable for StaticPairObject<SP> {
fn serialize(&self, serializer: &mut dyn Serializer) { fn serialize(&self, serializer: &mut dyn Serializer) {
let (a, b) = self.pair.s_elements(); let (a, b) = self.pair.elements();
a.serialize(serializer); a.serialize(serializer);
b.serialize(serializer); b.serialize(serializer);
} }
@ -105,13 +133,14 @@ impl<'a, Ctx: 'a + Context, SP: StaticPair<'a, Ctx>> Factory<'a, Ctx>
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: Rc<dyn Resolver<'a, Ctx>>, resolver: Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
let (fa, fb) = SP::factories(&self.factory_data); let (fa, fb) = SP::factories(&self.factory_data);
let a: SP::A = match fa.deserialize(deserializer, resolver.clone()) { let a: SP::A = match fa.deserialize(deserializer, resolver.clone(), addresses) {
Ok(a) => a, Ok(a) => a,
Err(error) => return Err(SP::from_error_a(&self.factory_data, error)), Err(error) => return Err(SP::from_error_a(&self.factory_data, error)),
}; };
let b: SP::B = match fb.deserialize(deserializer, resolver) { let b: SP::B = match fb.deserialize(deserializer, resolver, addresses) {
Ok(b) => b, Ok(b) => b,
Err(error) => return Err(SP::from_error_b(&self.factory_data, error)), Err(error) => return Err(SP::from_error_b(&self.factory_data, error)),
}; };

View File

@ -67,8 +67,8 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> Factory<'a, Ctx>
&self, &self,
deserializer: &mut dyn Deserializer, deserializer: &mut dyn Deserializer,
resolver: std::rc::Rc<dyn Resolver<'a, Ctx>>, resolver: std::rc::Rc<dyn Resolver<'a, Ctx>>,
addresses: &mut Addresses,
) -> ParseResult<'a, Ctx, Self> { ) -> ParseResult<'a, Ctx, Self> {
let mut addresses = Addresses::start();
let factory = self.factory.clone(); let factory = self.factory.clone();
let address = addresses.next(deserializer)?; let address = addresses.next(deserializer)?;
Ok(if address.point == HASH_ZEROS { Ok(if address.point == HASH_ZEROS {