335 lines
10 KiB
Rust
335 lines
10 KiB
Rust
//! Generic implementation for objects that are structured
|
|
//! like a pair of two other objects.
|
|
|
|
use std::ops::Deref;
|
|
|
|
use crate::rstd::*;
|
|
|
|
use super::*;
|
|
|
|
/// 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 {
|
|
/// First element's type. Must equal [`StaticPair::A`].
|
|
type SA: Serializable;
|
|
/// Second element's type. Must equal [`StaticPair::B`].
|
|
type SB: Serializable;
|
|
|
|
/// Borrow both elements.
|
|
fn elements(&self) -> (&Self::SA, &Self::SB);
|
|
/// Separate into elements.
|
|
fn into_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 [`InliningFactory`] be implemented.
|
|
pub trait StaticPair<'a, Ctx: Context<'a>>:
|
|
'a + StaticPairSerializable<SA = Self::A, SB = Self::B> + Sized
|
|
{
|
|
/// [Factory] data. May, depending on the usecase, include factory (factories) on the element(s).
|
|
type FactoryData: 'a + Send + Sync + Clone;
|
|
/// First element's type. Must equal [`StaticPairSerializable::SA`].
|
|
type A: MentionableBase<'a, Ctx, Fctr = Self::FA>;
|
|
/// Second element's type. Must equal [`StaticPairSerializable::SB`].
|
|
type B: MentionableBase<'a, Ctx, Fctr = Self::FB>;
|
|
/// First element's factory.
|
|
type FA: FactoryBase<'a, Ctx, Mtbl = Self::A> + ParseMode;
|
|
/// Second element's factory.
|
|
type FB: FactoryBase<'a, Ctx, Mtbl = Self::B> + ParseMode;
|
|
/// See [`FactoryBase::ParseError`].
|
|
type ParseError: 'a + Error;
|
|
|
|
/// Borrow both elements' factories.
|
|
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,
|
|
) -> Result<Self, Self::ParseError>;
|
|
/// Regularise the error returned while parsing the first element.
|
|
fn from_error_a(
|
|
factory_data: &Self::FactoryData,
|
|
error: ParseError<'a, Ctx, Self::FA>,
|
|
) -> Self::ParseError;
|
|
/// Regularise the error returned while parsing the second element.
|
|
fn from_error_b(
|
|
factory_data: &Self::FactoryData,
|
|
error: ParseError<'a, Ctx, Self::FB>,
|
|
) -> Self::ParseError;
|
|
/// Derive factory data from the object data.
|
|
fn factory_data(&self) -> Self::FactoryData;
|
|
}
|
|
|
|
/// Generic implementation of a [Mentionable] or [Atomic] for [StaticPair]s.
|
|
#[derive(Clone)]
|
|
pub struct StaticPairObject<SP> {
|
|
pair: SP,
|
|
}
|
|
|
|
impl<SP> From<SP> for StaticPairObject<SP> {
|
|
fn from(value: SP) -> Self {
|
|
StaticPairObject { pair: value }
|
|
}
|
|
}
|
|
|
|
impl<SP> AsRef<SP> for StaticPairObject<SP> {
|
|
fn as_ref(&self) -> &SP {
|
|
&self.pair
|
|
}
|
|
}
|
|
|
|
impl<SP> Deref for StaticPairObject<SP> {
|
|
type Target = SP;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.pair
|
|
}
|
|
}
|
|
|
|
/// Generic implementation of a [Factory] for [StaticPair]s.
|
|
pub struct StaticPairFactory<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> {
|
|
factory_data: SP::FactoryData,
|
|
}
|
|
|
|
impl<SP: StaticPairSerializable> StaticPairObject<SP> {
|
|
pub fn serialize_sp(pair: &SP, serializer: &mut dyn Serializer) {
|
|
let (a, b) = pair.elements();
|
|
a.serialize(serializer);
|
|
b.serialize(serializer);
|
|
}
|
|
}
|
|
|
|
impl<SP: StaticPairSerializable> Serializable for StaticPairObject<SP> {
|
|
fn serialize(&self, serializer: &mut dyn Serializer) {
|
|
Self::serialize_sp(&self.pair, serializer);
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> MentionableBase<'a, Ctx>
|
|
for StaticPairObject<SP>
|
|
{
|
|
type Fctr = StaticPairFactory<'a, Ctx, SP>;
|
|
|
|
fn factory(&self) -> Self::Fctr {
|
|
StaticPairFactory {
|
|
factory_data: self.pair.factory_data(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<SP> StaticPairObject<SP> {
|
|
pub fn points_typed_sp<'a, Ctx: Context<'a>>(
|
|
pair: &SP,
|
|
points: &mut impl PointsVisitor<'a, Ctx>,
|
|
) where
|
|
SP: StaticPair<'a, Ctx>,
|
|
SP::A: Mentionable<'a, Ctx>,
|
|
SP::B: Mentionable<'a, Ctx>,
|
|
{
|
|
let (a, b) = pair.elements();
|
|
a.points_typed(points);
|
|
b.points_typed(points);
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> MentionableTop<'a, Ctx> for StaticPairObject<SP>
|
|
where
|
|
SP::A: Mentionable<'a, Ctx>,
|
|
SP::B: Mentionable<'a, Ctx>,
|
|
{
|
|
fn points_typed(&self, points: &mut impl PointsVisitor<'a, Ctx>) {
|
|
Self::points_typed_sp(&self.pair, points);
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> Clone for StaticPairFactory<'a, Ctx, SP> {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
factory_data: self.factory_data.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> FactoryBase<'a, Ctx>
|
|
for StaticPairFactory<'a, Ctx, SP>
|
|
{
|
|
type Mtbl = StaticPairObject<SP>;
|
|
|
|
type ParseError = SP::ParseError;
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> ParseMode for StaticPairFactory<'a, Ctx, SP> {
|
|
type Mode = <SP::FB as ParseMode>::Mode;
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> StaticPairFactory<'a, Ctx, SP>
|
|
where
|
|
SP::FA: InliningFactory<'a, Ctx>,
|
|
SP::FB: FactoryModeParse<'a, Ctx>,
|
|
{
|
|
pub fn mdeserialize_sp<I: InCtx<'a, Ctx>>(
|
|
factory_data: &SP::FactoryData,
|
|
inctx: I,
|
|
) -> ModeResultP<Self, SP, SP::ParseError, I> {
|
|
let (fa, fb) = SP::factories(factory_data);
|
|
let (a, inctx) = fa
|
|
.ideserialize(inctx)
|
|
.map_err(|e| SP::from_error_a(factory_data, e))?;
|
|
Self::bind(
|
|
fb.mdeserialize(inctx)
|
|
.map_err(|e| SP::from_error_b(factory_data, e))?,
|
|
|b| SP::from_parsed(factory_data, a, b),
|
|
)
|
|
}
|
|
|
|
pub fn mextend_sp(
|
|
factory_data: &SP::FactoryData,
|
|
mentionable: ExtensionSourceP<Self, SP>,
|
|
tail: &[u8],
|
|
) -> ExtensionResultP<Self, SP, SP::ParseError> {
|
|
let (_, fb) = SP::factories(factory_data);
|
|
// annotated to help rust-analyzer
|
|
Self::xsbind::<SP, _, _, _>(
|
|
mentionable,
|
|
SP::into_elements,
|
|
|b| Self::xmap_err(fb.mextend(b, tail), |e| SP::from_error_b(factory_data, e)),
|
|
|a, b| SP::from_parsed(factory_data, a, b),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> FactoryModeParse<'a, Ctx>
|
|
for StaticPairFactory<'a, Ctx, SP>
|
|
where
|
|
SP::FA: InliningFactory<'a, Ctx>,
|
|
SP::FB: FactoryModeParse<'a, Ctx>,
|
|
{
|
|
fn mdeserialize<I: InCtx<'a, Ctx>>(&self, inctx: I) -> ModeResultM<'a, Ctx, Self, I> {
|
|
Ok(Self::map(
|
|
Self::mdeserialize_sp(&self.factory_data, inctx)?,
|
|
|pair| StaticPairObject { pair },
|
|
))
|
|
}
|
|
|
|
fn mextend(
|
|
&self,
|
|
mentionable: ExtensionSourceM<'a, Ctx, Self>,
|
|
tail: &[u8],
|
|
) -> ExtensionResultM<'a, Ctx, Self> {
|
|
Self::xbind(
|
|
Self::mextend_sp(
|
|
&self.factory_data,
|
|
Self::smap(mentionable, |StaticPairObject { pair }| pair),
|
|
tail,
|
|
),
|
|
|pair| Ok(StaticPairObject { pair }),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> FixedSizeFactory<'a, Ctx>
|
|
for StaticPairFactory<'a, Ctx, SP>
|
|
where
|
|
SP::FA: FixedSizeFactory<'a, Ctx>,
|
|
SP::FB: FixedSizeFactory<'a, Ctx> + FactoryModeParse<'a, Ctx>,
|
|
{
|
|
fn size(&self) -> usize {
|
|
let (fa, fb) = SP::factories(&self.factory_data);
|
|
fa.size() + fb.size()
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> ConstSizeFactory<'a, Ctx>
|
|
for StaticPairFactory<'a, Ctx, SP>
|
|
where
|
|
SP::FA: ConstSizeFactory<'a, Ctx>,
|
|
SP::FB: ConstSizeFactory<'a, Ctx> + FactoryModeParse<'a, Ctx>,
|
|
{
|
|
const SIZE: usize = SP::FA::SIZE + SP::FB::SIZE;
|
|
}
|
|
|
|
/// Atomic equivalent of [`StaticPair`].
|
|
///
|
|
/// Note: [`StaticPairAtomic::A`] requires [`InliningAtomic`] be implemented.
|
|
pub trait StaticPairAtomic:
|
|
'static + Send + Sync + Clone + Sized + StaticPairSerializable<SA = Self::A, SB = Self::B>
|
|
{
|
|
/// First element's type. Must equal [`StaticPairSerializable::SA`].
|
|
type A: AtomicBase + ParseMode;
|
|
/// Second element's type. Must equal [`StaticPairSerializable::SB`].
|
|
type B: AtomicBase + ParseMode;
|
|
|
|
type AParseError: Error;
|
|
/// Construct the atomic from the elements.
|
|
fn from_parsed(a: Self::A, b: Self::B) -> Result<Self, Self::AParseError>;
|
|
/// Regularise the error returned while parsing the first element.
|
|
fn from_error_a(error: AParseError<Self::A>) -> Self::AParseError;
|
|
/// Regularise the error returned while parsing the second element.
|
|
fn from_error_b(error: AParseError<Self::B>) -> Self::AParseError;
|
|
}
|
|
|
|
impl<SP: StaticPairAtomic> AtomicBase for StaticPairObject<SP> {
|
|
type AParseError = SP::AParseError;
|
|
}
|
|
|
|
impl<SP: StaticPairAtomic> ParseMode for StaticPairObject<SP> {
|
|
type Mode = <SP::B as ParseMode>::Mode;
|
|
}
|
|
|
|
impl<SP: StaticPairAtomic> StaticPairObject<SP>
|
|
where
|
|
SP::A: InliningAtomic,
|
|
SP::B: AtomicModeParse,
|
|
{
|
|
pub fn ma_deserialize_sp<I: Stream>(stream: I) -> ModeResultP<Self, SP, SP::AParseError, I> {
|
|
let (a, stream) =
|
|
<SP::A as InliningAtomic>::a_ideserialize(stream).map_err(|e| SP::from_error_a(e))?;
|
|
Self::bind(
|
|
<SP::B as AtomicModeParse>::ma_deserialize(stream).map_err(|e| SP::from_error_b(e))?,
|
|
|b| SP::from_parsed(a, b),
|
|
)
|
|
}
|
|
|
|
pub fn ma_extend_sp(
|
|
atomic: ExtensionSourceP<Self, SP>,
|
|
tail: &[u8],
|
|
) -> ExtensionResultP<Self, SP, SP::AParseError> {
|
|
Self::xsbind(
|
|
atomic,
|
|
SP::into_elements,
|
|
|b| {
|
|
Self::xmap_err(<SP::B as AtomicModeParse>::ma_extend(b, tail), |e| {
|
|
SP::from_error_b(e)
|
|
})
|
|
},
|
|
|a, b| SP::from_parsed(a, b),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<SP: StaticPairAtomic> AtomicModeParse for StaticPairObject<SP>
|
|
where
|
|
SP::A: InliningAtomic,
|
|
SP::B: AtomicModeParse,
|
|
{
|
|
fn ma_deserialize<I: Stream>(stream: I) -> AModeResultM<Self, I> {
|
|
Ok(Self::map(Self::ma_deserialize_sp(stream)?, |pair| {
|
|
StaticPairObject { pair }
|
|
}))
|
|
}
|
|
|
|
fn ma_extend(atomic: AExtensionSourceM<Self>, tail: &[u8]) -> AExtensionResultM<Self> {
|
|
Self::xbind(
|
|
Self::ma_extend_sp(Self::smap(atomic, |StaticPairObject { pair }| pair), tail),
|
|
|pair| Ok(StaticPairObject { pair }),
|
|
)
|
|
}
|
|
}
|