object_rainbow/impls/
option.rs

1use std::ops::Add;
2
3use generic_array::{ArrayLength, GenericArray};
4use typenum::{B0, B1, Bit, IsGreater, IsLess, ToInt, U1, U2, U255, U256};
5
6use crate::*;
7
8impl<T: ToOutput + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>, N: Niche<NeedsTag = B>, B: Bit>
9    ToOutput for Option<T>
10{
11    fn to_output(&self, output: &mut dyn Output) {
12        match self {
13            Some(value) => {
14                if B::BOOL {
15                    output.write(&[0]);
16                }
17                value.to_output(output);
18            }
19            None => {
20                if B::BOOL {
21                    output.write(&[1]);
22                }
23                output.write(N::niche().as_slice());
24            }
25        }
26    }
27}
28
29impl<T: Topological<E>, E: 'static> Topological<E> for Option<T> {
30    fn accept_points(&self, visitor: &mut impl PointVisitor<E>) {
31        self.iter_accept_points(visitor);
32    }
33}
34
35impl<T: Tagged> Tagged for Option<T> {
36    const TAGS: Tags = T::TAGS;
37}
38
39impl<
40    T: MaybeHasNiche<MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B, N: Add<B, Output = N>>>>,
41    B: Bit,
42    N: Unsigned,
43> Size for Option<T>
44{
45    type Size = N;
46}
47
48pub struct UnspecifiedOptionNiche;
49
50pub struct OptionNiche<N, K>(N, K);
51
52pub trait NextNiche {
53    type NextNiche<N: ArrayLength>;
54}
55
56pub trait WrapNext {
57    type Wrap<N: ArrayLength, J>;
58}
59
60impl WrapNext for B1 {
61    type Wrap<N: ArrayLength, J> = SomeNiche<OptionNiche<N, J>>;
62}
63
64impl WrapNext for B0 {
65    type Wrap<N: ArrayLength, J> = UnspecifiedOptionNiche;
66}
67
68impl<
69    K: IsGreater<U1, Output = B1>
70        + IsLess<U256, Output = B1>
71        + Add<B1, Output = J>
72        + IsLess<U255, Output = B>,
73    J,
74    B: WrapNext,
75> NextNiche for K
76{
77    type NextNiche<N: ArrayLength> = B::Wrap<N, J>;
78}
79
80impl<N: ArrayLength, K: ToInt<u8> + NextNiche> Niche for OptionNiche<N, K> {
81    type NeedsTag = B0;
82    type N = N;
83    fn niche() -> GenericArray<u8, Self::N> {
84        let mut niche = GenericArray::default();
85        niche[0] = K::INT;
86        niche
87    }
88    type Next = K::NextNiche<N>;
89}
90
91pub trait OptionNicheWrapper: Bit {
92    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>>;
93}
94
95impl OptionNicheWrapper for B0 {
96    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>> = Mn::Next;
97}
98
99impl OptionNicheWrapper for B1 {
100    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>> =
101        SomeNiche<OptionNiche<<<Mn as Niche>::N as Add<Self>>::Output, U2>>;
102}
103
104impl<
105    T: MaybeHasNiche<MnArray: MnArray<MaybeNiche = Mn>>,
106    Mn: Niche<NeedsTag = B, N: Add<B, Output: ArrayLength>>,
107    B: OptionNicheWrapper,
108> MaybeHasNiche for Option<T>
109{
110    type MnArray = B::Wrap<Mn>;
111}
112
113impl<
114    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
115    N: Niche<NeedsTag = B>,
116    B: Bit,
117    I: ParseInput,
118> Parse<I> for Option<T>
119{
120    fn parse(input: I) -> crate::Result<Self> {
121        ParseInline::parse_as_inline(input)
122    }
123}
124
125impl<
126    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
127    N: Niche<NeedsTag = B>,
128    B: Bit,
129    I: ParseInput,
130> ParseInline<I> for Option<T>
131{
132    fn parse_inline(input: &mut I) -> crate::Result<Self> {
133        if B::BOOL {
134            if input.parse_inline()? {
135                Ok(None)
136            } else {
137                Ok(Some(input.parse_inline()?))
138            }
139        } else {
140            input.parse_compare(N::N::USIZE, &N::niche())
141        }
142    }
143}
144
145impl<
146    T: Inline<E> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
147    N: Niche<NeedsTag = B>,
148    B: Bit,
149    E: 'static,
150> Object<E> for Option<T>
151{
152}
153
154impl<
155    T: Inline<E> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
156    N: Niche<NeedsTag = B>,
157    B: Bit,
158    E: 'static,
159> Inline<E> for Option<T>
160{
161}
162
163impl<
164    T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
165    N: Niche<NeedsTag = B>,
166    B: Bit,
167> ReflessObject for Option<T>
168{
169}
170
171impl<
172    T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
173    N: Niche<NeedsTag = B>,
174    B: Bit,
175> ReflessInline for Option<T>
176{
177}
178
179impl Equivalent<bool> for Option<()> {
180    fn into_equivalent(self) -> bool {
181        self.is_none()
182    }
183
184    fn from_equivalent(object: bool) -> Self {
185        (!object).then_some(())
186    }
187}
188
189impl<T, U: Equivalent<T>> Equivalent<Option<T>> for Option<U> {
190    fn into_equivalent(self) -> Option<T> {
191        self.map(U::into_equivalent)
192    }
193
194    fn from_equivalent(option: Option<T>) -> Self {
195        option.map(U::from_equivalent)
196    }
197}
198
199#[test]
200fn equivalent_to_bool() {
201    assert_eq!(false.vec(), Option::from_equivalent(false).vec());
202    assert_eq!(true.vec(), Option::from_equivalent(true).vec());
203}
204
205#[test]
206fn unit_none_is_1() {
207    assert_eq!(None::<()>.vec(), [1]);
208}
209
210#[test]
211fn unit_none_none_is_2() {
212    assert_eq!(None::<Option<()>>.vec(), [2]);
213}
214
215#[test]
216fn unit_none_none_none_is_3() {
217    assert_eq!(None::<Option<Option<()>>>.vec(), [3]);
218}