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