Skip to main content

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
8pub trait TaggedOption {
9    const TAGGED_OPTION: bool = true;
10    fn none_data() -> impl AsRef<[u8]> {
11        []
12    }
13}
14
15impl<T: MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>, N: Niche<NeedsTag = B>, B: Bit>
16    TaggedOption for T
17{
18    const TAGGED_OPTION: bool = B::BOOL;
19    fn none_data() -> impl AsRef<[u8]> {
20        N::niche()
21    }
22}
23
24impl<T: ToOutput + TaggedOption> ToOutput for Option<T> {
25    fn to_output(&self, output: &mut impl Output) {
26        match self {
27            Some(value) => {
28                if T::TAGGED_OPTION && output.is_real() {
29                    output.write(&[0]);
30                }
31                value.to_output(output);
32            }
33            None => {
34                if output.is_real() {
35                    if T::TAGGED_OPTION {
36                        output.write(&[1]);
37                    } else {
38                        output.write(T::none_data().as_ref());
39                    }
40                }
41            }
42        }
43    }
44}
45
46impl<T: InlineOutput + TaggedOption> InlineOutput for Option<T> {}
47
48impl<T: ListHashes> ListHashes for Option<T> {
49    fn list_hashes(&self, f: &mut impl FnMut(Hash)) {
50        self.iter_list_hashes(f);
51    }
52}
53
54impl<T: Topological> Topological for Option<T> {
55    fn traverse(&self, visitor: &mut impl PointVisitor) {
56        self.iter_traverse(visitor);
57    }
58}
59
60impl<T: Tagged> Tagged for Option<T> {
61    const TAGS: Tags = T::TAGS;
62}
63
64impl<
65    T: Size + MaybeHasNiche<MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B, N: Add<B, Output = N>>>>,
66    B: Bit,
67    N: Unsigned,
68> Size for Option<T>
69{
70    type Size = N;
71}
72
73pub struct UnspecifiedOptionNiche;
74
75pub struct OptionNiche<N, K>(N, K);
76
77pub trait NextNiche {
78    type NextNiche<N: ArrayLength>;
79}
80
81pub trait WrapNext {
82    type Wrap<N: ArrayLength, J>;
83}
84
85impl WrapNext for B1 {
86    type Wrap<N: ArrayLength, J> = SomeNiche<OptionNiche<N, J>>;
87}
88
89impl WrapNext for B0 {
90    type Wrap<N: ArrayLength, J> = UnspecifiedOptionNiche;
91}
92
93impl<
94    K: IsGreater<U1, Output = B1>
95        + IsLess<U256, Output = B1>
96        + Add<B1, Output = J>
97        + IsLess<U255, Output = B>,
98    J,
99    B: WrapNext,
100> NextNiche for K
101{
102    type NextNiche<N: ArrayLength> = B::Wrap<N, J>;
103}
104
105impl<N: ArrayLength, K: ToInt<u8> + NextNiche> Niche for OptionNiche<N, K> {
106    type NeedsTag = B0;
107    type N = N;
108    fn niche() -> GenericArray<u8, Self::N> {
109        let mut niche = GenericArray::default();
110        niche[0] = K::INT;
111        niche
112    }
113    type Next = K::NextNiche<N>;
114}
115
116pub trait OptionNicheWrapper: Bit {
117    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>>;
118}
119
120impl OptionNicheWrapper for B0 {
121    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>> = Mn::Next;
122}
123
124impl OptionNicheWrapper for B1 {
125    type Wrap<Mn: Niche<NeedsTag = Self, N: Add<Self, Output: ArrayLength>>> =
126        SomeNiche<OptionNiche<<<Mn as Niche>::N as Add<Self>>::Output, U2>>;
127}
128
129impl<
130    T: MaybeHasNiche<MnArray: MnArray<MaybeNiche = Mn>>,
131    Mn: Niche<NeedsTag = B, N: Add<B, Output: ArrayLength>>,
132    B: OptionNicheWrapper,
133> MaybeHasNiche for Option<T>
134{
135    type MnArray = B::Wrap<Mn>;
136}
137
138pub trait OptionParseBit<T, I>: Bit {
139    fn parse_option(input: I) -> crate::Result<Option<T>>;
140}
141
142impl<T: Parse<I>, I: ParseInput> OptionParseBit<T, I> for B1 {
143    fn parse_option(mut input: I) -> crate::Result<Option<T>> {
144        if input.parse_inline()? {
145            input.empty()?;
146            Ok(None)
147        } else {
148            Ok(Some(input.parse()?))
149        }
150    }
151}
152
153impl<
154    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
155    N: Niche<NeedsTag = B0>,
156    I: ParseInput,
157> OptionParseBit<T, I> for B0
158{
159    fn parse_option(input: I) -> crate::Result<Option<T>> {
160        Option::<T>::parse_as_inline(input)
161    }
162}
163
164pub trait OptionParseBitInline<T, I>: OptionParseBit<T, I> {
165    fn parse_option_inline(input: &mut I) -> crate::Result<Option<T>>;
166}
167
168impl<T: ParseInline<I>, I: ParseInput> OptionParseBitInline<T, I> for B1 {
169    fn parse_option_inline(input: &mut I) -> crate::Result<Option<T>> {
170        if input.parse_inline()? {
171            Ok(None)
172        } else {
173            Ok(Some(input.parse_inline()?))
174        }
175    }
176}
177
178impl<
179    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
180    N: Niche<NeedsTag = B0>,
181    I: ParseInput,
182> OptionParseBitInline<T, I> for B0
183{
184    fn parse_option_inline(input: &mut I) -> crate::Result<Option<T>> {
185        input.parse_compare(N::N::USIZE, &N::niche())
186    }
187}
188
189impl<
190    T: Parse<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B>>>,
191    B: OptionParseBit<T, I>,
192    I: ParseInput,
193> Parse<I> for Option<T>
194{
195    fn parse(input: I) -> crate::Result<Self> {
196        B::parse_option(input)
197    }
198}
199
200impl<
201    T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche: Niche<NeedsTag = B>>>,
202    B: OptionParseBitInline<T, I>,
203    I: ParseInput,
204> ParseInline<I> for Option<T>
205{
206    fn parse_inline(input: &mut I) -> crate::Result<Self> {
207        B::parse_option_inline(input)
208    }
209}
210
211impl Equivalent<bool> for Option<()> {
212    fn into_equivalent(self) -> bool {
213        self.is_none()
214    }
215
216    fn from_equivalent(object: bool) -> Self {
217        (!object).then_some(())
218    }
219}
220
221impl<T, U: Equivalent<T>> Equivalent<Option<T>> for Option<U> {
222    fn into_equivalent(self) -> Option<T> {
223        self.map(U::into_equivalent)
224    }
225
226    fn from_equivalent(option: Option<T>) -> Self {
227        option.map(U::from_equivalent)
228    }
229}
230
231assert_impl!(
232    impl<T, E> Inline<E> for Option<T>
233    where
234        T: Inline<E> + MaybeHasNiche<MnArray: MaybeNiche + Niche<NeedsTag = B0>>,
235        E: Clone,
236    {
237    }
238);
239
240assert_impl!(
241    impl<T, E> Inline<E> for Option<T>
242    where
243        T: Inline<E> + MaybeHasNiche<MnArray: MaybeNiche + Niche<NeedsTag = B1>>,
244        E: Clone,
245    {
246    }
247);
248
249assert_impl!(
250    impl<T, E> Object<E> for Option<T>
251    where
252        T: Object<E> + MaybeHasNiche<MnArray: MaybeNiche + Niche<NeedsTag = B1>>,
253        E: Clone,
254    {
255    }
256);
257
258#[test]
259fn equivalent_to_bool() {
260    assert_eq!(false.vec(), Option::from_equivalent(false).vec());
261    assert_eq!(true.vec(), Option::from_equivalent(true).vec());
262}
263
264#[test]
265fn unit_none_is_1() {
266    assert_eq!(None::<()>.vec(), [1]);
267}
268
269#[test]
270fn unit_none_none_is_2() {
271    assert_eq!(None::<Option<()>>.vec(), [2]);
272}
273
274#[test]
275fn unit_none_none_none_is_3() {
276    assert_eq!(None::<Option<Option<()>>>.vec(), [3]);
277}