object_rainbow/
niche.rs

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}