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