nlist/peano.rs
1//! Type-level integers which use a unary representation
2//!
3//! The operators on this type-level integer representation are
4//! implemented as associated types on the [`PeanoInt`] trait,
5//! and don't require bounds other than `PeanoInt` to use them.
6//!
7//! # Example
8//!
9//! Constructing an NList that's `A * B + C` long.
10//!
11//! ```rust
12//! use nlist::{NList, Peano, PeanoInt, peano, nlist};
13//!
14//! // returned list length: 3 * 0 + 1 == 1
15//! assert_eq!(make_nlist::<Peano!(3), Peano!(0), Peano!(1)>(), nlist![0]);
16//!
17//! // returned list length: 2 * 1 + 3 == 5
18//! assert_eq!(make_nlist::<Peano!(2), Peano!(1), Peano!(3)>(), nlist![0, 1, 4, 9, 16]);
19//!
20//! // returned list length: 3 * 2 + 1 == 7
21//! assert_eq!(make_nlist::<Peano!(3), Peano!(2), Peano!(1)>(), nlist![0, 1, 4, 9, 16, 25, 36]);
22//!
23//! // makes an NList<u64, A * B + C>
24//! const fn make_nlist<A, B, C>() -> NList<u64, peano::Add<peano::Mul<A, B>, C>>
25//! where
26//! A: PeanoInt,
27//! B: PeanoInt,
28//! C: PeanoInt,
29//! {
30//! // the recursive function that constructs the list
31//! const fn inner<L: PeanoInt>(index: u64) -> NList<u64, L> {
32//! nlist::rec_from_fn!(|| (index.pow(2), inner(index + 1)))
33//! }
34//!
35//! inner(0)
36//! }
37//!
38//! ```
39
40
41use core::{
42 cmp::{Eq, Ord, PartialEq, PartialOrd},
43 fmt,
44 hash::Hash,
45 marker::PhantomData,
46};
47
48
49use typewit::{TypeCmp, TypeEq, TypeNe};
50
51
52use crate::boolean::{Bool, BoolWitG, Boolean, And, Not};
53
54///////////////////////////////////////////////////////////////////////////////
55
56#[doc(no_inline)]
57pub use crate::{Peano, peano};
58
59mod peano_wit;
60
61pub use peano_wit::PeanoWit;
62
63mod from_const;
64
65/// [`typewit::TypeFn`] equivalents of peano type aliases
66pub mod type_fns;
67
68#[doc(no_inline)]
69pub use self::type_fns::*;
70
71
72#[doc(no_inline)]
73pub use typewit::const_marker::Usize;
74
75pub use self::from_const::{FromPeano, FromUsize, IntoPeano, IntoUsize};
76
77///////////////////////////////////////////////////////////////////////////////
78
79macro_rules! integer_methods {
80 () => (
81 /// The usize value of this integer
82 pub const fn usize(self) -> usize {
83 Self::USIZE
84 }
85 )
86}
87
88
89
90/// Type-level encoding of `0`
91#[derive(Copy, Clone)]
92pub struct Zero;
93
94impl Zero {
95 integer_methods!{}
96}
97
98
99/// Type-level encoding of `T + 1`
100pub struct PlusOne<T> {
101 /// `Self - 1`
102 pub sub_one: T,
103}
104
105impl<T: PeanoInt> PlusOne<T> {
106 integer_methods!{}
107}
108
109// The impls of std traits for Zero and PlusOne are all here
110mod std_impls;
111
112///////////////////////////////////////////////////////////////////////////////
113
114/// Type alias form of [`PeanoInt::SubOneSat`]
115pub type SubOneSat<Lhs> = <Lhs as PeanoInt>::SubOneSat;
116
117/// Type alias form of [`PeanoInt::IsZero`] chained with [`Boolean::IfTrue`]
118pub type IfZero<L, Then, Else> = <IsZero<L> as Boolean>::IfTrue<Then, Else>;
119
120/// Type alias form of [`PeanoInt::IsZero`] chained with [`Boolean::IfTruePI`]
121pub type IfZeroPI<L, Then, Else> = <IsZero<L> as Boolean>::IfTruePI<Then, Else>;
122
123/// Type alias form of [`PeanoInt::IsZero`]
124pub type IsZero<Lhs> = <Lhs as PeanoInt>::IsZero;
125
126/// Type alias form of [`PeanoInt::SubSat`]
127pub type SubSat<Lhs, Rhs> = <Lhs as PeanoInt>::SubSat<Rhs>;
128
129/// Type alias form of [`PeanoInt::Add`]
130pub type Add<Lhs, Rhs> = <Lhs as PeanoInt>::Add<Rhs>;
131
132/// Type alias form of [`PeanoInt::Mul`]
133pub type Mul<Lhs, Rhs> = <Lhs as PeanoInt>::Mul<Rhs>;
134
135/// Type alias form of [`PeanoInt::Min`]
136pub type Min<Lhs, Rhs> = <Lhs as PeanoInt>::Min<Rhs>;
137
138/// Type alias form of [`PeanoInt::Max`]
139pub type Max<Lhs, Rhs> = <Lhs as PeanoInt>::Max<Rhs>;
140
141/// Type alias form of [`PeanoInt::IsLe`]
142pub type IsLe<Lhs, Rhs> = <Lhs as PeanoInt>::IsLe<Rhs>;
143
144/// Type alias form of [`PeanoInt::IsLt`]
145pub type IsLt<Lhs, Rhs> = <Lhs as PeanoInt>::IsLt<Rhs>;
146
147
148
149/// Trait for a type-level unary encoding of unsigned integers.
150///
151/// Only [`Zero`] and [`PlusOne`] implement this trait,
152/// no other type can implement it.
153///
154/// # Example
155///
156/// Constructing a tuple `L`-levels deep with a recursive function.
157///
158/// ```rust
159/// use nlist::{Peano, peano};
160/// use nlist::peano::{PeanoInt, PeanoWit, PlusOne, Zero};
161/// use nlist::typewit::{CallFn, type_fn};
162///
163///
164/// assert_eq!(recursive::<Peano!(0)>(), ());
165/// assert_eq!(recursive::<Peano!(1)>(), (1, ()));
166/// assert_eq!(recursive::<Peano!(2)>(), (2, (1, ())));
167/// assert_eq!(recursive::<Peano!(3)>(), (3, (2, (1, ()))));
168///
169///
170/// // The `-> CallFn<PeanoToTupleFn<usize>, L>` return type
171/// // calls the `PeanoToTupleFn<usize>` type-level function with `L` as an argument.
172/// const fn recursive<L: PeanoToTuple>() -> CallFn<PeanoToTupleFn<usize>, L> {
173/// match L::PEANO_WIT {
174/// PeanoWit::PlusOne(len_te) => {
175/// len_te.project::<PeanoToTupleFn<usize>>()
176/// .to_left((L::USIZE, recursive::<L::SubOneSat>()))
177/// }
178/// PeanoWit::Zero(len_te) => {
179/// len_te.project::<PeanoToTupleFn<usize>>().to_left(())
180/// }
181/// }
182/// }
183///
184/// type_fn! {
185/// // `PeanoToTupleFn<T>` is a type-level function (`typewit::TypeFn` implementor)
186/// // from `L` to <L as PeanoToTuple>::Output::<T>
187/// struct PeanoToTupleFn<T>;
188///
189/// impl<L: PeanoToTuple> L => L::Output::<T>;
190/// }
191///
192/// trait PeanoToTuple: PeanoInt<SubOneSat = Self::SubOneSat_> {
193/// type SubOneSat_: PeanoToTuple;
194/// type Output<T>;
195/// }
196///
197/// impl PeanoToTuple for Zero {
198/// type SubOneSat_ = Zero;
199/// type Output<T> = ();
200/// }
201///
202/// impl<L: PeanoToTuple> PeanoToTuple for PlusOne<L> {
203/// type SubOneSat_ = L;
204/// type Output<T> = (T, L::Output<T>);
205/// }
206/// ```
207///
208pub trait PeanoInt:
209 Sized + Copy + Default + Hash + Sync + Send +
210 Eq + Ord + PartialEq + PartialEq<usize> + PartialOrd + PartialOrd<usize> +
211 fmt::Binary + fmt::Debug + fmt::Display + fmt::LowerHex + fmt::Octal + fmt::UpperHex +
212 'static
213{
214 /// Type level equivalent of `.saturating_sub(1)`
215 ///
216 /// # Example
217 ///
218 /// ```rust
219 /// use nlist::{PeanoInt, Peano, peano};
220 ///
221 /// assert_eq!(peano::SubOneSat::<Peano!(0)>::NEW, 0);
222 /// assert_eq!(peano::SubOneSat::<Peano!(1)>::NEW, 0);
223 /// assert_eq!(peano::SubOneSat::<Peano!(2)>::NEW, 1);
224 /// assert_eq!(peano::SubOneSat::<Peano!(3)>::NEW, 2);
225 ///
226 /// ```
227 type SubOneSat: PeanoInt;
228
229 #[doc(hidden)]
230 type __PairOfPeanos<R: PeanoInt>: PeanoCmpWit<L = Self, R = R>;
231
232 /// Whether `Self` is Zero
233 ///
234 /// # Example
235 ///
236 /// ```rust
237 /// use nlist::{PeanoInt, Peano, peano};
238 /// use nlist::boolean::Bool;
239 ///
240 /// let _: peano::IsZero<Peano!(0)> = Bool::<true>;
241 /// let _: peano::IsZero<Peano!(1)> = Bool::<false>;
242 /// let _: peano::IsZero<Peano!(2)> = Bool::<false>;
243 /// let _: peano::IsZero<Peano!(3)> = Bool::<false>;
244 ///
245 /// ```
246 type IsZero: Boolean;
247
248 /// Type level equivalent of `.saturating_sub(R)`
249 ///
250 /// # Example
251 ///
252 /// ```rust
253 /// use nlist::{PeanoInt, Peano, peano};
254 ///
255 /// assert_eq!(peano::SubSat::<Peano!(3), Peano!(0)>::NEW, 3);
256 /// assert_eq!(peano::SubSat::<Peano!(3), Peano!(1)>::NEW, 2);
257 /// assert_eq!(peano::SubSat::<Peano!(3), Peano!(2)>::NEW, 1);
258 /// assert_eq!(peano::SubSat::<Peano!(3), Peano!(3)>::NEW, 0);
259 /// assert_eq!(peano::SubSat::<Peano!(3), Peano!(4)>::NEW, 0);
260 /// ```
261 type SubSat<R: PeanoInt>: PeanoInt;
262
263 /// Computes the addition of `Self` and `Rhs`
264 ///
265 /// # Example
266 ///
267 /// ```rust
268 /// use nlist::{PeanoInt, Peano, peano};
269 ///
270 /// assert_eq!(peano::Add::<Peano!(0), Peano!(0)>::NEW, 0);
271 /// assert_eq!(peano::Add::<Peano!(0), Peano!(1)>::NEW, 1);
272 /// assert_eq!(peano::Add::<Peano!(0), Peano!(2)>::NEW, 2);
273 ///
274 /// assert_eq!(peano::Add::<Peano!(1), Peano!(0)>::NEW, 1);
275 /// assert_eq!(peano::Add::<Peano!(1), Peano!(1)>::NEW, 2);
276 /// assert_eq!(peano::Add::<Peano!(1), Peano!(2)>::NEW, 3);
277 ///
278 /// assert_eq!(peano::Add::<Peano!(2), Peano!(0)>::NEW, 2);
279 /// assert_eq!(peano::Add::<Peano!(2), Peano!(1)>::NEW, 3);
280 /// assert_eq!(peano::Add::<Peano!(2), Peano!(2)>::NEW, 4);
281 ///
282 /// ```
283 type Add<Rhs: PeanoInt>: PeanoInt;
284
285 /// Computes `Self` multiplied by `Rhs`
286 ///
287 /// # Example
288 ///
289 /// ```rust
290 /// use nlist::{PeanoInt, Peano, peano};
291 ///
292 /// assert_eq!(peano::Mul::<Peano!(0), Peano!(0)>::NEW, 0);
293 /// assert_eq!(peano::Mul::<Peano!(0), Peano!(1)>::NEW, 0);
294 ///
295 /// assert_eq!(peano::Mul::<Peano!(1), Peano!(0)>::NEW, 0);
296 /// assert_eq!(peano::Mul::<Peano!(1), Peano!(1)>::NEW, 1);
297 /// assert_eq!(peano::Mul::<Peano!(1), Peano!(2)>::NEW, 2);
298 ///
299 /// assert_eq!(peano::Mul::<Peano!(2), Peano!(1)>::NEW, 2);
300 /// assert_eq!(peano::Mul::<Peano!(2), Peano!(2)>::NEW, 4);
301 /// assert_eq!(peano::Mul::<Peano!(2), Peano!(3)>::NEW, 6);
302 ///
303 /// ```
304 type Mul<Rhs: PeanoInt>: PeanoInt;
305
306 /// Computes the minimum of `Self` and `Rhs`
307 ///
308 /// # Example
309 ///
310 /// ```rust
311 /// use nlist::{PeanoInt, Peano, peano};
312 ///
313 /// assert_eq!(peano::Min::<Peano!(0), Peano!(0)>::NEW, 0);
314 /// assert_eq!(peano::Min::<Peano!(0), Peano!(1)>::NEW, 0);
315 /// assert_eq!(peano::Min::<Peano!(0), Peano!(2)>::NEW, 0);
316 ///
317 /// assert_eq!(peano::Min::<Peano!(1), Peano!(0)>::NEW, 0);
318 /// assert_eq!(peano::Min::<Peano!(1), Peano!(1)>::NEW, 1);
319 /// assert_eq!(peano::Min::<Peano!(1), Peano!(2)>::NEW, 1);
320 ///
321 /// assert_eq!(peano::Min::<Peano!(2), Peano!(0)>::NEW, 0);
322 /// assert_eq!(peano::Min::<Peano!(2), Peano!(1)>::NEW, 1);
323 /// assert_eq!(peano::Min::<Peano!(2), Peano!(2)>::NEW, 2);
324 ///
325 /// ```
326 type Min<Rhs: PeanoInt>: PeanoInt;
327
328 /// Computes the maximum of `Self` and `Rhs`
329 ///
330 /// # Example
331 ///
332 /// ```rust
333 /// use nlist::{PeanoInt, Peano, peano};
334 ///
335 /// assert_eq!(peano::Max::<Peano!(0), Peano!(0)>::NEW, 0);
336 /// assert_eq!(peano::Max::<Peano!(0), Peano!(1)>::NEW, 1);
337 /// assert_eq!(peano::Max::<Peano!(0), Peano!(2)>::NEW, 2);
338 ///
339 /// assert_eq!(peano::Max::<Peano!(1), Peano!(0)>::NEW, 1);
340 /// assert_eq!(peano::Max::<Peano!(1), Peano!(1)>::NEW, 1);
341 /// assert_eq!(peano::Max::<Peano!(1), Peano!(2)>::NEW, 2);
342 ///
343 /// assert_eq!(peano::Max::<Peano!(2), Peano!(0)>::NEW, 2);
344 /// assert_eq!(peano::Max::<Peano!(2), Peano!(1)>::NEW, 2);
345 /// assert_eq!(peano::Max::<Peano!(2), Peano!(2)>::NEW, 2);
346 ///
347 /// ```
348 type Max<Rhs: PeanoInt>: PeanoInt;
349
350 /// Whether `Self < Rhs`
351 ///
352 /// # Example
353 ///
354 /// ```rust
355 /// use nlist::{Peano, peano};
356 /// use nlist::boolean::Bool;
357 ///
358 /// let _: peano::IsLt<Peano!(0), Peano!(0)> = Bool::<false>;
359 /// let _: peano::IsLt<Peano!(0), Peano!(1)> = Bool::<true>;
360 /// let _: peano::IsLt<Peano!(0), Peano!(2)> = Bool::<true>;
361 ///
362 /// let _: peano::IsLt<Peano!(1), Peano!(0)> = Bool::<false>;
363 /// let _: peano::IsLt<Peano!(1), Peano!(1)> = Bool::<false>;
364 /// let _: peano::IsLt<Peano!(1), Peano!(2)> = Bool::<true>;
365 ///
366 /// let _: peano::IsLt<Peano!(2), Peano!(0)> = Bool::<false>;
367 /// let _: peano::IsLt<Peano!(2), Peano!(1)> = Bool::<false>;
368 /// let _: peano::IsLt<Peano!(2), Peano!(2)> = Bool::<false>;
369 ///
370 /// ```
371 type IsLt<Rhs: PeanoInt>: Boolean;
372
373 /// Whether `Self <= Rhs`
374 ///
375 /// # Example
376 ///
377 /// ```rust
378 /// use nlist::{Peano, peano};
379 /// use nlist::boolean::Bool;
380 ///
381 /// let _: peano::IsLe<Peano!(0), Peano!(0)> = Bool::<true>;
382 /// let _: peano::IsLe<Peano!(0), Peano!(1)> = Bool::<true>;
383 /// let _: peano::IsLe<Peano!(0), Peano!(2)> = Bool::<true>;
384 ///
385 /// let _: peano::IsLe<Peano!(1), Peano!(0)> = Bool::<false>;
386 /// let _: peano::IsLe<Peano!(1), Peano!(1)> = Bool::<true>;
387 /// let _: peano::IsLe<Peano!(1), Peano!(2)> = Bool::<true>;
388 ///
389 /// let _: peano::IsLe<Peano!(2), Peano!(0)> = Bool::<false>;
390 /// let _: peano::IsLe<Peano!(2), Peano!(1)> = Bool::<false>;
391 /// let _: peano::IsLe<Peano!(2), Peano!(2)> = Bool::<true>;
392 ///
393 /// ```
394 type IsLe<Rhs: PeanoInt>: Boolean;
395
396 /// Constructs this type
397 ///
398 /// # Example
399 ///
400 /// ```rust
401 /// use nlist::{PeanoInt, Peano};
402 ///
403 /// let int = <Peano!(2)>::NEW;
404 ///
405 /// assert_eq!(int, 2);
406 /// ```
407 const NEW: Self;
408
409 /// What integer value `Self` represents.
410 ///
411 /// # Example
412 ///
413 /// ```rust
414 /// use nlist::{PeanoInt, Peano};
415 ///
416 /// assert_eq!(<Peano!(3)>::USIZE, 3);
417 /// assert_eq!(<Peano!(5)>::USIZE, 5);
418 /// ```
419 const USIZE: usize;
420
421 /// A type witness for whether `Self` is `Zero` or `PlusOne`
422 ///
423 /// For an example, you can look at the docs of [`PeanoWit`] itself
424 ///
425 const PEANO_WIT: PeanoWit<Self>;
426}
427
428impl PeanoInt for Zero {
429 type SubOneSat = Zero;
430
431 #[doc(hidden)]
432 type __PairOfPeanos<R: PeanoInt> = PairOfPeanos<Self, R>;
433
434 type IsZero = Bool<true>;
435
436 type SubSat<R: PeanoInt> = Zero;
437
438 type Add<Rhs: PeanoInt> = Rhs;
439
440 type Mul<Rhs: PeanoInt> = Zero;
441
442 type Min<Rhs: PeanoInt> = Zero;
443
444 type Max<Rhs: PeanoInt> = Rhs;
445
446 type IsLt<Rhs: PeanoInt> = Not<Rhs::IsZero>;
447
448 type IsLe<Rhs: PeanoInt> = Bool<true>;
449
450 const NEW: Self = Zero;
451
452 const USIZE: usize = 0;
453
454 const PEANO_WIT: PeanoWit<Self> = PeanoWit::Zero(TypeEq::NEW);
455}
456
457impl<T> PeanoInt for PlusOne<T>
458where
459 T: PeanoInt,
460{
461 type SubOneSat = T;
462
463 #[doc(hidden)]
464 type __PairOfPeanos<R: PeanoInt> = PairOfPeanos<Self, R>;
465
466 type IsZero = Bool<false>;
467
468 type SubSat<R: PeanoInt> = IfZeroPI<R, Self, T::SubSat<R::SubOneSat>>;
469
470 type Add<Rhs: PeanoInt> = PlusOne<T::Add<Rhs>>;
471
472 type Mul<Rhs: PeanoInt> = Add<Mul<T, Rhs>, Rhs>;
473
474 type Min<Rhs: PeanoInt> = IfZeroPI<Rhs, Zero, PlusOne<T::Min<Rhs::SubOneSat>>>;
475
476 type Max<Rhs: PeanoInt> = PlusOne<IfZeroPI<Rhs, T, T::Max<Rhs::SubOneSat>>>;
477
478 type IsLt<Rhs: PeanoInt> = And<Not<Rhs::IsZero>, T::IsLt<Rhs::SubOneSat>>;
479
480 type IsLe<Rhs: PeanoInt> = And<Not<Rhs::IsZero>, T::IsLe<Rhs::SubOneSat>>;
481
482 const NEW: Self = PlusOne { sub_one: T::NEW };
483
484 const USIZE: usize = 1 + T::USIZE;
485
486 const PEANO_WIT: PeanoWit<Self> = PeanoWit::PlusOne(TypeEq::NEW);
487}
488
489mod pair_of_peanos;
490
491use self::pair_of_peanos::{PairOfPeanos, PeanoCmpWit, PairOfPeanos_};
492
493pub mod proofs;
494
495
496
497////////////////////////////////////////////////////////////////////////////////
498
499/// Converts the peano integer to a usize
500///
501/// # Example
502///
503/// ```rust
504/// use nlist::peano;
505///
506/// assert_eq!(peano::to_usize(peano!(0)), 0);
507/// assert_eq!(peano::to_usize(peano!(1)), 1);
508/// assert_eq!(peano::to_usize(peano!(2)), 2);
509/// assert_eq!(peano::to_usize(peano!(3)), 3);
510///
511/// ```
512pub const fn to_usize<I: PeanoInt>(_: I) -> usize {
513 I::USIZE
514}
515
516////////////////////////////////////////////////////////////////////////////////
517
518
519/// Returns a [`TypeCmp<L, R>`], which is a proof of whether `L == R` or `L != R`.
520///
521/// # Example
522///
523/// Coercing an [`NList`](crate::NList) to a specific length
524///
525/// ```rust
526/// use nlist::{NList, Peano, PeanoInt, nlist, peano};
527///
528/// assert_eq!(try_coerce(nlist![0; 0]), None);
529/// assert_eq!(try_coerce(nlist![3]), None);
530/// assert_eq!(try_coerce(nlist![3, 5]), None);
531/// assert_eq!(try_coerce(nlist![3, 5, 8]), Some(nlist![3, 5, 8]));
532/// assert_eq!(try_coerce(nlist![3, 5, 8, 13]), None);
533/// assert_eq!(try_coerce(nlist![3, 5, 8, 13, 21]), None);
534///
535/// const fn try_coerce<T, L>(list: NList<T, L>) -> Option<NList<T, Peano!(3)>>
536/// where
537/// T: Copy,
538/// L: PeanoInt
539/// {
540/// match peano::eq::<L, Peano!(3)>().eq() {
541/// Some(te) => Some(list.coerce_len(te)),
542/// None => {
543/// // works around "destructor cannot be evaluated at compile-time" error
544/// list.assert_copy_drop();
545///
546/// None
547/// }
548/// }
549/// }
550/// ```
551pub const fn eq<L, R>() -> TypeCmp<L, R>
552where
553 L: PeanoInt,
554 R: PeanoInt,
555{
556 PairOfPeanos_::<L, R>::EQ_WIT
557}
558
559const fn zero_one_inequality<L: PeanoInt>() -> TypeNe<Zero, PlusOne<L>> {
560 typewit::type_ne!(<L: PeanoInt> Zero, PlusOne<L>)
561}
562
563
564
565typewit::inj_type_fn! {
566 struct PlusOneFn;
567
568 impl<L: PeanoInt> L => PlusOne<L>;
569}
570
571
572
573/// Diverges when given a proof of `PlusOne<L> == Zero`
574/// (which is a contradiction, because they're different types).
575pub const fn contradiction<L>(length_te: TypeEq<PlusOne<L>, Zero>) -> ! {
576 typewit::type_fn! {
577 struct ZeroEqualsOneFn<T, U>;
578
579 impl<L> PlusOne<L> => T;
580 impl Zero => U;
581 }
582
583 length_te.map(ZeroEqualsOneFn::NEW).to_left(())
584}