//! 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 + 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> + InliningFactory<'a, Ctx>; /// 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; /// 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 { pair: SP, } impl From for StaticPairObject { fn from(value: SP) -> Self { StaticPairObject { pair: value } } } impl AsRef for StaticPairObject { fn as_ref(&self) -> &SP { &self.pair } } impl Deref for StaticPairObject { 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 Serializable for StaticPairObject { fn serialize(&self, serializer: &mut dyn Serializer) { let (a, b) = self.pair.elements(); a.serialize(serializer); b.serialize(serializer); } } impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> MentionableBase<'a, Ctx> for StaticPairObject { type Fctr = StaticPairFactory<'a, Ctx, SP>; fn factory(&self) -> Self::Fctr { StaticPairFactory { factory_data: self.pair.factory_data(), } } } impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> MentionableTop<'a, Ctx> for StaticPairObject where SP::A: Mentionable<'a, Ctx>, SP::B: Mentionable<'a, Ctx>, { fn points_typed(&self, points: &mut impl PointsVisitor<'a, Ctx>) { let (a, b) = self.pair.elements(); a.points_typed(points); b.points_typed(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; type ParseError = SP::ParseError; } impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> ParseMode for StaticPairFactory<'a, Ctx, SP> { type Mode = ::Mode; } impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> FactoryModeParse<'a, Ctx> for StaticPairFactory<'a, Ctx, SP> where SP::FB: FactoryModeParse<'a, Ctx>, { fn mdeserialize>(&self, inctx: I) -> ModeResultM<'a, Ctx, Self, I> { let (fa, fb) = SP::factories(&self.factory_data); let (a, inctx) = fa .ideserialize(inctx) .map_err(|e| SP::from_error_a(&self.factory_data, e))?; Self::bind( fb.mdeserialize(inctx) .map_err(|e| SP::from_error_b(&self.factory_data, e))?, |b| SP::from_parsed(&self.factory_data, a, b).map(|pair| StaticPairObject { pair }), ) } fn mextend( &self, mentionable: ExtensionSourceM<'a, Ctx, Self>, tail: &[u8], ) -> ExtensionResultM<'a, Ctx, Self> { let (_, fb) = SP::factories(&self.factory_data); Self::xsbind( mentionable, |StaticPairObject { pair }| pair.into_elements(), |b| { Self::xmap_err(fb.mextend(b, tail), |e| { SP::from_error_b(&self.factory_data, e) }) }, |a, b| SP::from_parsed(&self.factory_data, a, b).map(|pair| 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; } pub trait StaticPairAtomic: 'static + Send + Sync + Clone + Sized + StaticPairSerializable { /// 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; /// Regularise the error returned while parsing the first element. fn from_error_a(error: AParseError) -> Self::AParseError; /// Regularise the error returned while parsing the second element. fn from_error_b(error: AParseError) -> Self::AParseError; } impl AtomicBase for StaticPairObject { type AParseError = SP::AParseError; } impl ParseMode for StaticPairObject { type Mode = ::Mode; } impl AtomicModeParse for StaticPairObject where SP::A: InliningAtomic, SP::B: AtomicModeParse, { fn ma_deserialize(stream: I) -> AModeResultM { let (a, stream) = ::a_ideserialize(stream).map_err(|e| SP::from_error_a(e))?; Self::bind( ::ma_deserialize(stream).map_err(|e| SP::from_error_b(e))?, |b| SP::from_parsed(a, b).map(|pair| StaticPairObject { pair }), ) } fn ma_extend(atomic: AExtensionSourceM, tail: &[u8]) -> AExtensionResultM { Self::xsbind( atomic, |StaticPairObject { pair }| pair.into_elements(), |b| { Self::xmap_err(::ma_extend(b, tail), |e| { SP::from_error_b(e) }) }, |a, b| SP::from_parsed(a, b).map(|pair| StaticPairObject { pair }), ) } }