[![Crates.io](https://img.shields.io/crates/v/gnat.svg)](https://crates.io/crates/gnat)
[![Documentation](https://docs.rs/gnat/badge.svg)](https://docs.rs/gnat)
[![Rust](https://img.shields.io/badge/rust-1.90.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/rust)

<!-- cargo-reedme: start -->

<!-- cargo-reedme: info-start

    Do not edit this region by hand
    ===============================

    This region was generated from Rust documentation comments by `cargo-reedme` using this command:

        cargo +nightly reedme --all-features

    for more info: https://github.com/nik-rev/cargo-reedme

cargo-reedme: info-end -->

This crate provides type-level natural numbers, similar to [`typenum`](https://docs.rs/typenum/latest/typenum/).

A type-level number is a type that represents a number. The [`Nat`](https://docs.rs/gnat/latest/gnat/trait.Nat.html) trait takes the role of the
“type-level number type”, i.e. one accepts a type-level number using a generic parameter with
bound [`Nat`](https://docs.rs/gnat/latest/gnat/trait.Nat.html).

The use cases are the same as those of generic consts.

`gnat` differs from `typenum` in that its [`Nat`](https://docs.rs/gnat/latest/gnat/trait.Nat.html) trait is not a marker trait, but defines
enough structure (through hidden generic associated types) to be able to define and use
generic operations on it, without any extra bounds.
As such, this crate is more expressive than `typenum` and `generic_const_exprs`.

For details about defining custom operations, see the [`expr`](https://docs.rs/gnat/latest/gnat/expr/) module documentation.

# Some motivating examples
#### Concatenating arrays at compile time
Using `generic_const_exprs` or `typenum`/`generic-array`:
```rust
#![feature(generic_const_exprs)]
const fn concat_arrays_gcex<T, const M: usize, const N: usize>(
    a: [T; M],
    b: [T; N],
) -> [T; M + N]
where
    [T; M + N]:, // Required well-formedness bound
{
    todo!() // Possible with unsafe code
}

use generic_array::{GenericArray, ArrayLength};
const fn concat_arrays_tnum<T, M: ArrayLength, N: ArrayLength>(
    a: GenericArray<T, M>,
    b: GenericArray<T, N>,
) -> GenericArray<T, typenum::op!(M + N)>
where // ArrayLength is not enough, we also need to add a bound for `+`
    M: std::ops::Add<N, Output: ArrayLength>,
{
    todo!() // Possible with unsafe code
}
```
Using this crate:
```rust
use gnat::{Nat, array::Arr};
const fn concat_arrays_gnat<T, M: Nat, N: Nat>(
    a: Arr<T, M>,
    b: Arr<T, N>,
) -> Arr<T, gnat::eval!(M + N)> { // No extra bounds!
    a.concat_arr(b).retype() // There is even a method for this :)
}
```
#### Const Recursion
Naively writing a function that recurses over the const parameter is impossible in
`generic_const_exprs` and `typenum`, since the recursive argument needs the same
bounds as the parameter:
```rust
#![feature(generic_const_exprs)]
fn recursive_gcex<const N: usize>() -> u32
where
    [(); N / 2]:, // The argument must be well-formed
    [(); (N / 2) / 2]:, // The argument's argument must be well-formed
    // ... need infinitely many bounds, even though N converges to 0
{
    if N == 0 {
        0
    } else {
        // The bounds above for N need to imply the same bounds for N / 2
        recursive_gce::<{ N / 2 }>() + 1
    }
}

use {std::ops::Div, typenum::{P2, Unsigned}};
fn recursive_tnum<N>() -> u32
where
    N: Unsigned + Div<P2>,
    N::Output: Unsigned + Div<P2>,
    <N::Output as Div<P2>>::Output: Unsigned + Div<P2>,
    // ... again, we would need this to repeat infinitely often
{
    if N::USIZE == 0 { // (Pretend this correctly handles overflow)
        0
    } else {
        recursive_gce::<typenum::op!(N / 2)>() + 1
    }
}
```
While this can be expressed using a helper trait like `trait RecDiv2: Unsigned { type Output: RecDiv2;  }`,
it is combersome and leaks into the bounds of every other calling function.

Since this crate does not require such bounds, the naive implementation just works:
```rust
fn recursive_gnat<N: gnat::Nat>() -> u32 {
    if gnat::is_zero::<N>() {
        0
    } else {
        recursive_gnat::<gnat::eval!(N / 2)>() + 1
    }
}
assert_eq!(recursive_gnat::<gnat::lit!(10)>(), 4); // 10 5 2 1 0
```

<!-- cargo-reedme: end -->
