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