object_rainbow/impls/
option.rs1use 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<E>, E: 'static> Topological<E> for Option<T> {
44 fn accept_points(&self, visitor: &mut impl PointVisitor<E>) {
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
127impl<
128 T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
129 N: Niche<NeedsTag = B>,
130 B: Bit,
131 I: ParseInput,
132> Parse<I> for Option<T>
133{
134 fn parse(input: I) -> crate::Result<Self> {
135 ParseInline::parse_as_inline(input)
136 }
137}
138
139impl<
140 T: ParseInline<I> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
141 N: Niche<NeedsTag = B>,
142 B: Bit,
143 I: ParseInput,
144> ParseInline<I> for Option<T>
145{
146 fn parse_inline(input: &mut I) -> crate::Result<Self> {
147 if B::BOOL {
148 if input.parse_inline()? {
149 Ok(None)
150 } else {
151 Ok(Some(input.parse_inline()?))
152 }
153 } else {
154 input.parse_compare(N::N::USIZE, &N::niche())
155 }
156 }
157}
158
159impl<
160 T: Inline<E> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
161 N: Niche<NeedsTag = B>,
162 B: Bit,
163 E: 'static,
164> Object<E> for Option<T>
165{
166}
167
168impl<
169 T: Inline<E> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
170 N: Niche<NeedsTag = B>,
171 B: Bit,
172 E: 'static,
173> Inline<E> for Option<T>
174{
175}
176
177impl<
178 T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
179 N: Niche<NeedsTag = B>,
180 B: Bit,
181> ReflessObject for Option<T>
182{
183}
184
185impl<
186 T: ReflessInline + MaybeHasNiche<MnArray: MnArray<MaybeNiche = N>>,
187 N: Niche<NeedsTag = B>,
188 B: Bit,
189> ReflessInline for Option<T>
190{
191}
192
193impl Equivalent<bool> for Option<()> {
194 fn into_equivalent(self) -> bool {
195 self.is_none()
196 }
197
198 fn from_equivalent(object: bool) -> Self {
199 (!object).then_some(())
200 }
201}
202
203impl<T, U: Equivalent<T>> Equivalent<Option<T>> for Option<U> {
204 fn into_equivalent(self) -> Option<T> {
205 self.map(U::into_equivalent)
206 }
207
208 fn from_equivalent(option: Option<T>) -> Self {
209 option.map(U::from_equivalent)
210 }
211}
212
213#[test]
214fn equivalent_to_bool() {
215 assert_eq!(false.vec(), Option::from_equivalent(false).vec());
216 assert_eq!(true.vec(), Option::from_equivalent(true).vec());
217}
218
219#[test]
220fn unit_none_is_1() {
221 assert_eq!(None::<()>.vec(), [1]);
222}
223
224#[test]
225fn unit_none_none_is_2() {
226 assert_eq!(None::<Option<()>>.vec(), [2]);
227}
228
229#[test]
230fn unit_none_none_none_is_3() {
231 assert_eq!(None::<Option<Option<()>>>.vec(), [3]);
232}