//! 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> + 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; /// 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 StaticPairObject { pub fn serialize_sp(pair: &SP, serializer: &mut dyn Serializer) { let (a, b) = pair.elements(); a.serialize(serializer); b.serialize(serializer); } } impl Serializable for StaticPairObject { 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 { type Fctr = StaticPairFactory<'a, Ctx, SP>; fn factory(&self) -> Self::Fctr { StaticPairFactory { factory_data: self.pair.factory_data(), } } } impl StaticPairObject { 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 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; 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>> StaticPairFactory<'a, Ctx, SP> where SP::FA: InliningFactory<'a, Ctx>, SP::FB: FactoryModeParse<'a, Ctx>, { pub fn mdeserialize_sp>( factory_data: &SP::FactoryData, inctx: I, ) -> ModeResultP { 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, tail: &[u8], ) -> ExtensionResultP { let (_, fb) = SP::factories(factory_data); // annotated to help rust-analyzer Self::xsbind::( 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>(&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 { /// 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 StaticPairObject where SP::A: InliningAtomic, SP::B: AtomicModeParse, { pub fn ma_deserialize_sp(stream: I) -> ModeResultP { 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), ) } pub fn ma_extend_sp( atomic: ExtensionSourceP, tail: &[u8], ) -> ExtensionResultP { Self::xsbind( atomic, SP::into_elements, |b| { Self::xmap_err(::ma_extend(b, tail), |e| { SP::from_error_b(e) }) }, |a, b| SP::from_parsed(a, b), ) } } impl AtomicModeParse for StaticPairObject where SP::A: InliningAtomic, SP::B: AtomicModeParse, { fn ma_deserialize(stream: I) -> AModeResultM { Ok(Self::map(Self::ma_deserialize_sp(stream)?, |pair| { StaticPairObject { pair } })) } fn ma_extend(atomic: AExtensionSourceM, tail: &[u8]) -> AExtensionResultM { Self::xbind( Self::ma_extend_sp(Self::smap(atomic, |StaticPairObject { pair }| pair), tail), |pair| Ok(StaticPairObject { pair }), ) } }