object-rainbow 0.0.0-a.4

distributed object model
Documentation
use std::ops::Add;

use generic_array::{ArrayLength, GenericArray};
use typenum::{B0, B1, Bit};

use crate::*;

impl<T: ToOutput + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>, N: Niche<NeedsTag = B>, B: Bit>
    ToOutput for Option<T>
{
    fn to_output(&self, output: &mut dyn Output) {
        match self {
            Some(value) => {
                if B::BOOL {
                    output.write(&[0]);
                }
                value.to_output(output);
            }
            None => {
                if B::BOOL {
                    output.write(&[1]);
                }
                output.write(N::niche().as_slice());
            }
        }
    }
}

impl<T: Topological> Topological for Option<T> {
    fn accept_points(&self, visitor: &mut impl PointVisitor) {
        self.iter_accept_points(visitor);
    }
}

impl<T: Tagged> Tagged for Option<T> {
    const TAGS: Tags = T::TAGS;
}

impl<
    T: MaybeHasNiche<MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B, N: Add<B, Output = N>>>>,
    B: Bit,
    N: Unsigned,
> Size for Option<T>
{
    type Size = N;
}

pub struct OptionNiche<N>(N);

impl<N: ArrayLength> Niche for OptionNiche<N> {
    type NeedsTag = B0;
    type N = N;
    fn niche() -> GenericArray<u8, Self::N> {
        let mut niche = GenericArray::default();
        niche[0] = 2;
        niche
    }
}

pub trait OptionNicheWrapper: Bit {
    type Wrap<N: ArrayLength>: MaybeNiche;
}

impl OptionNicheWrapper for B0 {
    type Wrap<N: ArrayLength> = NoNiche<ZeroNoNiche<N>>;
}

impl OptionNicheWrapper for B1 {
    type Wrap<N: ArrayLength> = SomeNiche<OptionNiche<N>>;
}

impl<
    T: MaybeHasNiche<
        MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B, N: Add<B, Output: ArrayLength>>>,
    >,
    B: OptionNicheWrapper,
> MaybeHasNiche for Option<T>
{
    type MnArray = B::Wrap<<Self as Size>::Size>;
}

impl<
    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
    N: Niche<NeedsTag = B>,
    B: Bit,
    I: ParseInput,
> Parse<I> for Option<T>
{
    fn parse(input: I) -> crate::Result<Self> {
        ParseInline::parse_as_inline(input)
    }
}

impl<
    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
    N: Niche<NeedsTag = B>,
    B: Bit,
    I: ParseInput,
> ParseInline<I> for Option<T>
{
    fn parse_inline(input: &mut I) -> crate::Result<Self> {
        if B::BOOL {
            if input.parse_inline()? {
                Ok(None)
            } else {
                Ok(Some(input.parse_inline()?))
            }
        } else {
            input.parse_compare(N::N::USIZE, &N::niche())
        }
    }
}

impl<T: Inline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>, N: Niche<NeedsTag = B>, B: Bit>
    Object for Option<T>
{
}

impl<T: Inline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>, N: Niche<NeedsTag = B>, B: Bit>
    Inline for Option<T>
{
}

impl<
    T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
    N: Niche<NeedsTag = B>,
    B: Bit,
> ReflessObject for Option<T>
{
}

impl<
    T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
    N: Niche<NeedsTag = B>,
    B: Bit,
> ReflessInline for Option<T>
{
}

impl Equivalent<bool> for Option<()> {
    fn into_equivalent(self) -> bool {
        self.is_none()
    }

    fn from_equivalent(object: bool) -> Self {
        (!object).then_some(())
    }
}

#[test]
fn equivalent() {
    assert_eq!(
        false.output::<Vec<u8>>(),
        Option::from_equivalent(false).output::<Vec<u8>>(),
    );
    assert_eq!(
        true.output::<Vec<u8>>(),
        Option::from_equivalent(true).output::<Vec<u8>>(),
    );
}