radn-rs/src/rstd/inlining/static_pair.rs
2023-07-29 09:26:32 +00:00

222 lines
7.1 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);
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 [`InlineableFactory`] be implemented.
pub trait StaticPair<'a, Ctx: Context<'a>>:
'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 + 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> + InlineableFactory<'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) -> Self;
/// 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] for [StaticPair]s.
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> Serializable for StaticPairObject<SP> {
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<SP>
{
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<SP>
where
SP::A: MentionableTop<'a, Ctx>,
SP::B: MentionableTop<'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<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>> RegularFactory<'a, Ctx>
for StaticPairFactory<'a, Ctx, SP>
where
SP::FB: RegularFactory<'a, Ctx>,
{
fn rdeserialize(&self, inctx: impl InCtx<'a, Ctx>) -> ParseResult<'a, Ctx, Self> {
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))?;
let b = fb
.rdeserialize(inctx)
.map_err(|e| SP::from_error_b(&self.factory_data, e))?;
Ok(StaticPairObject {
pair: SP::from_parsed(&self.factory_data, a, b),
})
}
fn rextend(&self, mentionable: Self::Mtbl, tail: &[u8]) -> ParseResult<'a, Ctx, Self> {
let (_, fb) = SP::factories(&self.factory_data);
let (a, b) = mentionable.pair.into_elements();
match fb.rextend(b, tail) {
Ok(b) => Ok(SP::from_parsed(&self.factory_data, a, b).into()),
Err(e) => Err(SP::from_error_b(&self.factory_data, e)),
}
}
}
impl<'a, Ctx: Context<'a>, SP: StaticPair<'a, Ctx>> InlineableFactory<'a, Ctx>
for StaticPairFactory<'a, Ctx, SP>
where
SP::FB: InlineableFactory<'a, Ctx>,
{
fn extension_error(&self, tail: &[u8]) -> Self::ParseError {
let (_, fb) = SP::factories(&self.factory_data);
SP::from_error_b(&self.factory_data, fb.extension_error(tail))
}
fn ideserialize<I: InCtx<'a, Ctx>>(&self, inctx: I) -> IParseResult<'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))?;
let (b, inctx) = fb
.ideserialize(inctx)
.map_err(|e| SP::from_error_b(&self.factory_data, e))?;
Ok((
StaticPairObject {
pair: SP::from_parsed(&self.factory_data, a, b),
},
inctx,
))
}
}
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>,
{
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>,
{
const SIZE: usize = SP::FA::SIZE + SP::FB::SIZE;
}