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