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