1use std::ops::Add;
2
3use generic_array::{ArrayLength, GenericArray, functional::FunctionalSequence, sequence::Concat};
4use typenum::{ATerm, B0, B1, Bit, Sum, TArr, U0, Unsigned};
5
6use crate::{
7 Enum, Size, SizeExt, ToOutput,
8 enumkind::{EnumKind, UsizeTag},
9};
10
11pub trait MaybeHasNiche {
12 type MnArray;
13}
14
15pub struct NoNiche<V>(V);
16pub struct NoNiche2<A, B>(A, B);
17pub struct AndNiche<V, T>(V, T);
18pub struct NicheAnd<T, V>(T, V);
19pub struct SomeNiche<T>(T);
20
21pub trait Niche {
22 type NeedsTag: Bit;
23 type N: ArrayLength;
24 fn niche() -> GenericArray<u8, Self::N>;
25 type Next;
26}
27
28pub trait MaybeNiche {
29 type N: Unsigned;
30}
31
32pub trait AsTailOf<U: MaybeNiche>: MaybeNiche {
33 type WithHead: MaybeNiche;
34}
35
36pub trait AsHeadOf<U: MaybeNiche>: MaybeNiche {
37 type WithTail: MaybeNiche;
38}
39
40impl<V: Niche<NeedsTag = B1>> Niche for NoNiche<V> {
41 type NeedsTag = B1;
42 type N = V::N;
43 fn niche() -> GenericArray<u8, Self::N> {
44 V::niche()
45 }
46 type Next = Self;
47}
48
49impl<V: Niche<NeedsTag = B1>> MaybeNiche for NoNiche<V> {
50 type N = V::N;
51}
52
53impl<U: MaybeNiche<N: Add<V::N, Output: Unsigned>>, V: Niche<NeedsTag = B1>> AsTailOf<U>
54 for NoNiche<V>
55{
56 type WithHead = NoNiche2<U, Self>;
57}
58
59impl<V: Niche<NeedsTag = B1>, U: AsTailOf<Self>> AsHeadOf<U> for NoNiche<V> {
60 type WithTail = U::WithHead;
61}
62
63impl<A: Niche<N: Add<B::N, Output: ArrayLength>>, B: Niche> Niche for NoNiche2<A, B> {
64 type NeedsTag = B1;
65 type N = Sum<A::N, B::N>;
66 fn niche() -> GenericArray<u8, Self::N> {
67 Concat::concat(A::niche(), B::niche())
68 }
69 type Next = NoNiche<Self>;
70}
71
72impl<A: MaybeNiche<N: Add<B::N, Output: Unsigned>>, B: MaybeNiche> MaybeNiche for NoNiche2<A, B> {
73 type N = Sum<A::N, B::N>;
74}
75
76impl<
77 U: MaybeNiche<N: Add<Sum<A::N, B::N>, Output: Unsigned>>,
78 A: MaybeNiche<N: Add<B::N, Output: Unsigned>>,
79 B: MaybeNiche,
80> AsTailOf<U> for NoNiche2<A, B>
81{
82 type WithHead = NoNiche2<U, Self>;
83}
84
85impl<A: MaybeNiche<N: Add<B::N, Output: Unsigned>>, B: MaybeNiche, U: AsTailOf<Self>> AsHeadOf<U>
86 for NoNiche2<A, B>
87{
88 type WithTail = U::WithHead;
89}
90
91impl<
92 V: Niche<N = N, NeedsTag: NicheAuto>,
93 N: ArrayLength + Add<T::N, Output: ArrayLength>,
94 T: Niche,
95> Niche for AndNiche<V, T>
96{
97 type NeedsTag = T::NeedsTag;
98 type N = Sum<N, T::N>;
99 fn niche() -> GenericArray<u8, Self::N> {
100 Concat::concat(V::niche(), T::niche())
101 }
102 type Next = AndNiche<AutoNiche<V>, T::Next>;
103}
104
105impl<V: MaybeNiche<N = N>, N: Unsigned, T: MaybeNiche> MaybeNiche for AndNiche<V, T>
106where
107 N: Add<T::N, Output: Unsigned>,
108{
109 type N = Sum<N, T::N>;
110}
111
112impl<
113 U: MaybeNiche<N: Add<Sum<N, T::N>, Output: Unsigned>>,
114 V: MaybeNiche<N = N>,
115 N: Unsigned,
116 T: MaybeNiche,
117> AsTailOf<U> for AndNiche<V, T>
118where
119 N: Add<T::N, Output: Unsigned>,
120{
121 type WithHead = AndNiche<U, Self>;
122}
123
124impl<V: MaybeNiche<N = N>, N: Unsigned, T: MaybeNiche, U: MaybeNiche> AsHeadOf<U> for AndNiche<V, T>
125where
126 N: Add<T::N, Output: Unsigned>,
127 Sum<N, T::N>: Add<U::N, Output: Unsigned>,
128{
129 type WithTail = NicheAnd<Self, U>;
130}
131
132impl<T: Niche<N: Add<N, Output: ArrayLength>>, V: Niche<N = N, NeedsTag: NicheAuto>, N: ArrayLength>
133 Niche for NicheAnd<T, V>
134{
135 type NeedsTag = T::NeedsTag;
136 type N = Sum<T::N, N>;
137 fn niche() -> GenericArray<u8, Self::N> {
138 Concat::concat(T::niche(), V::niche())
139 }
140 type Next = NicheAnd<T::Next, AutoNiche<V>>;
141}
142
143impl<T: MaybeNiche<N: Add<N, Output: Unsigned>>, V: MaybeNiche<N = N>, N: Unsigned> MaybeNiche
144 for NicheAnd<T, V>
145{
146 type N = Sum<T::N, N>;
147}
148
149impl<
150 U: MaybeNiche<N: Add<Sum<T::N, N>, Output: Unsigned>>,
151 T: MaybeNiche<N: Add<N, Output: Unsigned>>,
152 V: MaybeNiche<N = N>,
153 N: Unsigned,
154> AsTailOf<U> for NicheAnd<T, V>
155{
156 type WithHead = AndNiche<U, Self>;
157}
158
159impl<T: MaybeNiche<N: Add<N, Output: Unsigned>>, V: MaybeNiche<N = N>, N: Unsigned, U: MaybeNiche>
160 AsHeadOf<U> for NicheAnd<T, V>
161where
162 Sum<T::N, N>: Add<U::N, Output: Unsigned>,
163{
164 type WithTail = NicheAnd<Self, U>;
165}
166
167impl<T: Niche<NeedsTag = B0>> Niche for SomeNiche<T> {
168 type NeedsTag = T::NeedsTag;
169 type N = T::N;
170 fn niche() -> GenericArray<u8, Self::N> {
171 T::niche()
172 }
173 type Next = T::Next;
174}
175
176impl<T: Niche<NeedsTag = B0>> MaybeNiche for SomeNiche<T> {
177 type N = T::N;
178}
179
180impl<U: MaybeNiche<N: Add<T::N, Output: Unsigned>>, T: Niche<NeedsTag = B0>> AsTailOf<U>
181 for SomeNiche<T>
182{
183 type WithHead = AndNiche<U, Self>;
184}
185
186impl<T: Niche<N: Add<U::N, Output: Unsigned>, NeedsTag = B0>, U: MaybeNiche> AsHeadOf<U>
187 for SomeNiche<T>
188{
189 type WithTail = NicheAnd<Self, U>;
190}
191
192pub trait MnArray {
193 type MaybeNiche: MaybeNiche;
194}
195
196impl MnArray for ATerm {
197 type MaybeNiche = NoNiche<ZeroNoNiche<U0>>;
198}
199
200impl<T: MaybeNiche> MnArray for T {
201 type MaybeNiche = T;
202}
203
204impl<T: AsHeadOf<R::MaybeNiche>, R: MnArray> MnArray for TArr<T, R> {
205 type MaybeNiche = T::WithTail;
206}
207
208pub struct ZeroNoNiche<N>(N);
209
210impl<N: ArrayLength> Niche for ZeroNoNiche<N> {
211 type NeedsTag = B1;
212 type N = N;
213 fn niche() -> GenericArray<u8, Self::N> {
214 GenericArray::default()
215 }
216 type Next = NoNiche<Self>;
217}
218
219pub struct ZeroNiche<N, Next = NoNiche<ZeroNoNiche<N>>>(N, Next);
220
221impl<N: ArrayLength, Next> Niche for ZeroNiche<N, Next> {
222 type NeedsTag = B0;
223 type N = N;
224 fn niche() -> GenericArray<u8, Self::N> {
225 GenericArray::default()
226 }
227 type Next = Next;
228}
229
230pub struct OneNiche<N>(N);
231
232impl<N: ArrayLength> Niche for OneNiche<N> {
233 type NeedsTag = B0;
234 type N = N;
235 fn niche() -> GenericArray<u8, Self::N> {
236 GenericArray::default().map(|()| 0xff)
237 }
238 type Next = NoNiche<ZeroNoNiche<N>>;
239}
240
241pub trait NicheOr: MaybeNiche {
242 type NicheOr<U: NicheOr<N = Self::N>>: NicheOr<N = Self::N>;
243 fn index(index: usize) -> usize;
244}
245
246impl<V: Niche<NeedsTag = B1>> NicheOr for NoNiche<V> {
247 type NicheOr<U: NicheOr<N = Self::N>> = U;
248 fn index(index: usize) -> usize {
249 index + 1
250 }
251}
252
253impl<A: MaybeNiche<N: Add<B::N, Output: Unsigned>>, B: MaybeNiche> NicheOr for NoNiche2<A, B> {
254 type NicheOr<U: NicheOr<N = Self::N>> = U;
255 fn index(index: usize) -> usize {
256 index + 1
257 }
258}
259
260impl<V: MaybeNiche<N = N>, N: Unsigned + Add<T::N, Output: Unsigned>, T: MaybeNiche> NicheOr
261 for AndNiche<V, T>
262{
263 type NicheOr<U: NicheOr<N = Self::N>> = Self;
264 fn index(_: usize) -> usize {
265 0
266 }
267}
268
269impl<T: MaybeNiche<N: Add<N, Output: Unsigned>>, V: MaybeNiche<N = N>, N: Unsigned> NicheOr
270 for NicheAnd<T, V>
271{
272 type NicheOr<U: NicheOr<N = Self::N>> = Self;
273 fn index(_: usize) -> usize {
274 0
275 }
276}
277
278impl<T: Niche<NeedsTag = B0>> NicheOr for SomeNiche<T> {
279 type NicheOr<U: NicheOr<N = Self::N>> = Self;
280 fn index(_: usize) -> usize {
281 0
282 }
283}
284
285pub trait NicheFoldOr {
286 type Or: NicheOr;
287 fn index() -> usize;
288}
289
290impl<T: MnArray<MaybeNiche: NicheOr>> NicheFoldOr for TArr<T, ATerm> {
291 type Or = T::MaybeNiche;
292 fn index() -> usize {
293 0
294 }
295}
296
297impl<T: NicheOr, A: NicheFoldOr<Or: MaybeNiche<N = T::N>>> NicheFoldOr for TArr<T, A> {
298 type Or = T::NicheOr<A::Or>;
299 fn index() -> usize {
300 T::index(A::index())
301 }
302}
303
304pub struct NicheFoldOrArray<T>(T);
305
306impl<T: NicheFoldOr> MnArray for NicheFoldOrArray<T> {
307 type MaybeNiche = T::Or;
308}
309
310pub struct EnumNiche<E, const X: usize>(E);
311
312impl<
313 E: Enum<Kind = K>,
314 K: EnumKind<Tag = T>,
315 T: UsizeTag + ToOutput + Size<Size = N> + MaybeHasNiche<MnArray: MnArray<MaybeNiche = V>>,
316 V: Niche<N = N>,
317 N: ArrayLength,
318 const X: usize,
319> Niche for EnumNiche<E, X>
320{
321 type NeedsTag = V::NeedsTag;
322 type N = N;
323 fn niche() -> GenericArray<u8, Self::N> {
324 if V::NeedsTag::BOOL {
325 T::from_usize(X).to_array()
326 } else {
327 V::niche()
328 }
329 }
330 type Next = NoNiche<ZeroNoNiche<N>>;
331}
332
333pub trait NicheAuto: Bit {
334 type Auto<T: Niche<NeedsTag = Self>>: MaybeNiche<N = T::N>;
335}
336
337impl NicheAuto for B0 {
338 type Auto<T: Niche<NeedsTag = Self>> = SomeNiche<T>;
339}
340
341impl NicheAuto for B1 {
342 type Auto<T: Niche<NeedsTag = Self>> = NoNiche<T>;
343}
344
345pub type AutoNiche<T> = <<T as Niche>::NeedsTag as NicheAuto>::Auto<T>;
346
347pub type AutoEnumNiche<E, const X: usize> = AutoNiche<EnumNiche<E, X>>;
348
349pub struct HackNiche<const X: usize>;
350
351impl<const X: usize> Niche for HackNiche<X> {
352 type NeedsTag = B1;
353 type N = U0;
354 fn niche() -> GenericArray<u8, Self::N> {
355 GenericArray::default()
356 }
357 type Next = NoNiche<Self>;
358}