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}