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