1use core::ops::{Add, Sub};
10use std::marker::PhantomData;
11pub use typenum;
12use typenum::{Bit, Diff, Sum, UInt, Unsigned, U0};
13
14#[derive(Debug)]
19pub struct Absorb<N>(PhantomData<N>);
20#[derive(Debug)]
22pub struct Squeeze<N>(PhantomData<N>);
23
24pub trait IOWord: private::Sealed {}
26
27impl<N: Unsigned> IOWord for Absorb<N> {}
28impl<N: Unsigned> IOWord for Squeeze<N> {}
29
30pub trait List: private::Sealed {
35 fn unit() -> Self;
38
39 fn is_empty() -> bool;
41}
42
43impl<Item: IOWord, Next: List> List for Cons<Item, Next> {
44 fn unit() -> Self {
45 Cons {
46 _phantom: PhantomData,
47 }
48 }
49 fn is_empty() -> bool {
50 false
51 }
52}
53
54impl List for Nil {
55 fn unit() -> Self {
56 Nil
57 }
58 fn is_empty() -> bool {
59 true
60 }
61}
62
63#[derive(Debug)]
65pub struct Cons<Item, Next: List> {
66 _phantom: PhantomData<(Item, Next)>,
67}
68
69#[derive(Debug)]
71pub struct Nil;
72
73#[macro_export]
75macro_rules! iopat {
76 () => { $crate::traits::Nil };
77 (...$rest:ty) => { $rest };
78 ($a:ty) => { $crate::iopat![$a,] };
79 ($a:ty, $($tok:tt)*) => {
80 $crate::traits::Cons<$a, $crate::iopat![$($tok)*]>
81 };
82}
83
84pub trait Normalize: List {
88 type Output: List;
90}
91
92pub type Norm<T> = <T as Normalize>::Output;
94
95impl Normalize for Nil {
97 type Output = Nil;
98}
99
100impl<L: Normalize> Normalize for Cons<Squeeze<U0>, L> {
102 type Output = Norm<L>;
103}
104
105impl<L: Normalize> Normalize for Cons<Absorb<U0>, L> {
106 type Output = Norm<L>;
107}
108
109impl<U: Unsigned, B: Bit> Normalize for Cons<Absorb<UInt<U, B>>, Nil> {
111 type Output = Cons<Absorb<UInt<U, B>>, Nil>;
112}
113impl<U: Unsigned, B: Bit> Normalize for Cons<Squeeze<UInt<U, B>>, Nil> {
114 type Output = Cons<Squeeze<UInt<U, B>>, Nil>;
115}
116
117impl<U: Unsigned, B: Bit, M: Unsigned, T: List> Normalize
119 for Cons<Absorb<UInt<U, B>>, Cons<Absorb<M>, T>>
120where
121 UInt<U, B>: Add<M>, Cons<Absorb<Sum<UInt<U, B>, M>>, T>: Normalize,
123{
124 type Output = Norm<Cons<Absorb<Sum<UInt<U, B>, M>>, T>>;
125}
126
127impl<U: Unsigned, B: Bit, M: Unsigned, T: List> Normalize
128 for Cons<Squeeze<UInt<U, B>>, Cons<Squeeze<M>, T>>
129where
130 UInt<U, B>: Add<M>, Cons<Squeeze<Sum<UInt<U, B>, M>>, T>: Normalize,
132{
133 type Output = Norm<Cons<Squeeze<Sum<UInt<U, B>, M>>, T>>;
134}
135
136impl<U: Unsigned, B: Bit, U2: Unsigned, B2: Bit, T: List> Normalize
139 for Cons<Squeeze<UInt<U, B>>, Cons<Absorb<UInt<U2, B2>>, T>>
140where
141 Cons<Absorb<UInt<U2, B2>>, T>: Normalize,
142{
143 type Output = Cons<Squeeze<UInt<U, B>>, Norm<Cons<Absorb<UInt<U2, B2>>, T>>>;
144}
145
146impl<U: Unsigned, B: Bit, U2: Unsigned, B2: Bit, T: List> Normalize
147 for Cons<Absorb<UInt<U, B>>, Cons<Squeeze<UInt<U2, B2>>, T>>
148where
149 Cons<Squeeze<UInt<U2, B2>>, T>: Normalize,
150{
151 type Output = Cons<Absorb<UInt<U, B>>, Norm<Cons<Squeeze<UInt<U2, B2>>, T>>>;
152}
153
154impl<U: Unsigned, B: Bit, T: List> Normalize for Cons<Squeeze<UInt<U, B>>, Cons<Absorb<U0>, T>>
156where
157 Cons<Squeeze<UInt<U, B>>, T>: Normalize,
158{
159 type Output = Norm<Cons<Squeeze<UInt<U, B>>, T>>;
160}
161
162impl<U: Unsigned, B: Bit, T: List> Normalize for Cons<Absorb<UInt<U, B>>, Cons<Squeeze<U0>, T>>
163where
164 Cons<Absorb<UInt<U, B>>, T>: Normalize,
165{
166 type Output = Norm<Cons<Absorb<UInt<U, B>>, T>>;
167}
168
169pub trait Consume<Op: IOWord> {
174 type Output: List;
176}
177
178#[allow(dead_code)]
180pub type Use<T, U> = <T as Consume<U>>::Output;
181
182impl<N, T: List> Consume<Absorb<U0>> for Cons<Absorb<N>, T>
189where
190 N: Unsigned,
191{
192 type Output = Self;
193}
194
195impl<N, T: List> Consume<Squeeze<U0>> for Cons<Squeeze<N>, T>
196where
197 N: Unsigned,
198{
199 type Output = Self;
200}
201
202impl<U, B, N, T> Consume<Absorb<UInt<U, B>>> for Cons<Absorb<N>, T>
204where
205 U: Unsigned,
206 B: Bit,
207 N: Unsigned,
208 T: List,
209 N: Sub<UInt<U, B>>, Cons<Absorb<Diff<N, UInt<U, B>>>, T>: Normalize,
211{
212 type Output = Norm<Cons<Absorb<Diff<N, UInt<U, B>>>, T>>;
213}
214
215impl<U, B, N, T> Consume<Squeeze<UInt<U, B>>> for Cons<Squeeze<N>, T>
216where
217 U: Unsigned,
218 B: Bit,
219 N: Unsigned,
220 T: List,
221 N: Sub<UInt<U, B>>, Cons<Squeeze<Diff<N, UInt<U, B>>>, T>: Normalize,
223{
224 type Output = Norm<Cons<Squeeze<Diff<N, UInt<U, B>>>, T>>;
225}
226
227mod private {
229 pub trait Sealed {}
230
231 impl<N> Sealed for super::Absorb<N> {}
232 impl<N> Sealed for super::Squeeze<N> {}
233
234 impl Sealed for super::Nil {}
235 impl<H, T: super::List> Sealed for super::Cons<H, T> {}
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241 use typenum::assert_type_eq;
242 use typenum::{U1, U2, U3, U4, U5, U6};
243
244 #[test]
245 fn normalizes() {
246 assert_type_eq!(Norm<iopat![Absorb<U2>, Absorb<U3>]>, iopat![Absorb<U5>]);
248 assert_type_eq!(Norm<iopat![Squeeze<U2>, Squeeze<U3>]>, iopat![Squeeze<U5>]);
249 assert_type_eq!(
251 Norm<iopat![Squeeze<U2>, Absorb<U3>]>,
252 iopat![Squeeze<U2>, Absorb<U3>]
253 );
254 assert_type_eq!(
255 Norm<iopat![Squeeze<U2>, Squeeze<U3>, Absorb<U1>]>,
256 iopat![Squeeze<U5>, Absorb<U1>]
257 );
258 assert_type_eq!(Norm<iopat![Absorb<U0>, Absorb<U3>]>, iopat![Absorb<U3>]);
260 assert_type_eq!(Norm<iopat![Absorb<U0>, Squeeze<U3>]>, iopat![Squeeze<U3>]);
261 assert_type_eq!(Norm<iopat![Squeeze<U0>, Squeeze<U3>]>, iopat![Squeeze<U3>]);
262 assert_type_eq!(Norm<iopat![Squeeze<U0>, Absorb<U3>]>, iopat![Absorb<U3>]);
263 assert_type_eq!(
265 Norm<iopat![Absorb<U3>, Squeeze<U0>, Absorb<U1>]>,
266 iopat![Absorb<U4>]
267 );
268 assert_type_eq!(
269 Norm<iopat![Squeeze<U3>, Absorb<U0>, Squeeze<U1>]>,
270 iopat![Squeeze<U4>]
271 );
272 }
273
274 #[test]
275 fn uses() {
276 assert_type_eq!(
278 Use<iopat![Absorb<U5>], Absorb<U2>>,
279 iopat![Absorb<U3>]
280 );
281 assert_type_eq!(
282 Use<iopat![Absorb<U5>, Squeeze<U2>], Absorb<U2>>,
283 iopat![Absorb<U3>, Squeeze<U2>]
284 );
285
286 assert_type_eq!(
287 Use<iopat![Squeeze<U5>], Squeeze<U2>>,
288 iopat![Squeeze<U3>]
289 );
290 assert_type_eq!(
291 Use<iopat![Squeeze<U5>, Absorb<U2>], Squeeze<U2>>,
292 iopat![Squeeze<U3>, Absorb<U2>]
293 );
294
295 assert_type_eq!(Use<iopat![Absorb<U5>], Absorb<U5>>, Nil);
297 assert_type_eq!(
298 Use<iopat![Absorb<U5>], Absorb<U0>>,
299 iopat![Absorb<U5>]
300 );
301 assert_type_eq!(
302 Use<iopat![Squeeze<U5>], Squeeze<U0>>,
303 iopat![Squeeze<U5>]
304 );
305 assert_type_eq!(
306 Use<iopat![Absorb<U3>, Squeeze<U2>], Absorb<U3>>,
307 iopat![Squeeze<U2>]
308 );
309
310 assert_type_eq!(
321 Use<Use<iopat![Squeeze<U3>, Absorb<U5>, Absorb<U1>], Squeeze<U3>>, Absorb<U6>>,
322 Nil
323 );
324 }
325}