1use reify_reflect_core::{Reflect, RuntimeValue};
4use std::marker::PhantomData;
5
6#[derive(Default, Debug, Clone, Copy)]
17pub struct Z;
18
19#[derive(Default, Debug, Clone, Copy)]
33pub struct S<N>(pub PhantomData<N>);
34
35pub trait Nat {
47 fn to_u64() -> u64;
49}
50
51impl Nat for Z {
52 fn to_u64() -> u64 {
53 0
54 }
55}
56
57impl<N: Nat> Nat for S<N> {
58 fn to_u64() -> u64 {
59 1 + N::to_u64()
60 }
61}
62
63impl Reflect for Z {
64 type Value = RuntimeValue;
65
66 fn reflect() -> Self::Value {
67 RuntimeValue::Nat(0)
68 }
69}
70
71impl<N: Nat> Reflect for S<N> {
72 type Value = RuntimeValue;
73
74 fn reflect() -> Self::Value {
75 RuntimeValue::Nat(<S<N> as Nat>::to_u64())
76 }
77}
78
79pub trait Add<Rhs> {
98 type Result: Nat;
100}
101
102impl<N: Nat> Add<N> for Z {
104 type Result = N;
105}
106
107impl<M: Nat + Add<N>, N: Nat> Add<N> for S<M>
109where
110 <M as Add<N>>::Result: Nat,
111{
112 type Result = S<<M as Add<N>>::Result>;
113}
114
115pub trait Mul<Rhs> {
130 type Result: Nat;
132}
133
134impl<N: Nat> Mul<N> for Z {
136 type Result = Z;
137}
138
139impl<M, N> Mul<N> for S<M>
141where
142 M: Nat + Mul<N>,
143 N: Nat + Add<<M as Mul<N>>::Result>,
144 <M as Mul<N>>::Result: Nat,
145 <N as Add<<M as Mul<N>>::Result>>::Result: Nat,
146{
147 type Result = <N as Add<<M as Mul<N>>::Result>>::Result;
148}
149
150pub trait Lt<Rhs> {
165 const VALUE: bool;
167}
168
169impl Lt<Z> for Z {
171 const VALUE: bool = false;
172}
173
174impl<N: Nat> Lt<S<N>> for Z {
176 const VALUE: bool = true;
177}
178
179impl<M: Nat> Lt<Z> for S<M> {
181 const VALUE: bool = false;
182}
183
184impl<M: Nat + Lt<N>, N: Nat> Lt<S<N>> for S<M> {
186 const VALUE: bool = <M as Lt<N>>::VALUE;
187}
188
189pub type N0 = Z;
195pub type N1 = S<N0>;
197pub type N2 = S<N1>;
199pub type N3 = S<N2>;
201pub type N4 = S<N3>;
203pub type N5 = S<N4>;
205pub type N6 = S<N5>;
207pub type N7 = S<N6>;
209pub type N8 = S<N7>;
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn zero_reflects_to_nat_0() {
218 assert_eq!(Z::reflect(), RuntimeValue::Nat(0));
219 }
220
221 #[test]
222 fn successor_reflects_correctly() {
223 assert_eq!(S::<Z>::reflect(), RuntimeValue::Nat(1));
224 assert_eq!(<S<S<Z>>>::reflect(), RuntimeValue::Nat(2));
225 assert_eq!(<S<S<S<Z>>>>::reflect(), RuntimeValue::Nat(3));
226 }
227
228 #[test]
229 fn nat_to_u64() {
230 assert_eq!(Z::to_u64(), 0);
231 assert_eq!(<S<Z>>::to_u64(), 1);
232 assert_eq!(<S<S<S<S<S<Z>>>>>>::to_u64(), 5);
233 }
234
235 #[test]
236 fn type_aliases() {
237 assert_eq!(N0::to_u64(), 0);
238 assert_eq!(N1::to_u64(), 1);
239 assert_eq!(N5::to_u64(), 5);
240 assert_eq!(N8::to_u64(), 8);
241 }
242
243 #[test]
244 fn addition() {
245 assert_eq!(<<Z as Add<N3>>::Result as Nat>::to_u64(), 3);
247 assert_eq!(<<N2 as Add<N3>>::Result as Nat>::to_u64(), 5);
249 assert_eq!(<<N1 as Add<N0>>::Result as Nat>::to_u64(), 1);
251 }
252
253 #[test]
254 fn multiplication() {
255 assert_eq!(<<Z as Mul<N3>>::Result as Nat>::to_u64(), 0);
257 assert_eq!(<<N2 as Mul<N3>>::Result as Nat>::to_u64(), 6);
259 assert_eq!(<<N1 as Mul<N5>>::Result as Nat>::to_u64(), 5);
261 assert_eq!(<<N3 as Mul<N1>>::Result as Nat>::to_u64(), 3);
263 }
264
265 #[test]
266 #[allow(clippy::assertions_on_constants)]
267 fn less_than() {
268 assert!(!<Z as Lt<Z>>::VALUE);
269 assert!(<Z as Lt<S<Z>>>::VALUE);
270 assert!(!<S<Z> as Lt<Z>>::VALUE);
271 assert!(<N2 as Lt<N5>>::VALUE);
272 assert!(!<N5 as Lt<N2>>::VALUE);
273 assert!(!<N3 as Lt<N3>>::VALUE);
274 }
275
276 #[test]
277 fn reflect_returns_runtime_value() {
278 assert_eq!(N5::reflect(), RuntimeValue::Nat(5));
279 assert_eq!(N0::reflect(), RuntimeValue::Nat(0));
280 }
281}