I am the author of `sosecrets-rs`

where right now, I am trying to write a `RTSecret<T, MEC: typenum::Unsigned>`

struct where `T`

is any type and `MEC`

is an unsigned integer at the type level from the `typenum`

crate (e.g. `U69`

), etc. The crate counts the number of times (tracked by an internal counter of type `UnsafeCell<SomeUIntType>`

) the secret is revealed and returns an `Error`

or panic if it is revealed more than `MEC`

- materialized as runtime value - number of times.

I have an internal counter of type `UnsafeCell<SomeUIntType>`

, because the user of my crate at his compile time will fill in the type argument for the type parameter `MEC`

, e.g.

```
// How a user will use this `RTSecret` at his compile time.
let runtime_secret = RTSecret::<i32, typenum::consts::U69>::new(69);
```

and since the user of my crate let '`MEC`

' to be equal to `U69`

, that means `u8`

would suffice as my internal counter, e.g. of type `UnsafeCell<u8>`

since the internal counter will always starts from 0 and counting up by 1 until it reaches 69.

So I want to be able to derive the minimally representable unsigned integer type, supporting **only** `u8`

, `u16`

, `u32`

and `u64`

(and not `usize`

or `u128`

) from the type parameter `MEC: Unsigned`

only. I have a working solution that uses two type parameters, `MEC`

and `SIZE`

, `SIZE`

allows users to specify the exact type that they want the counter to be, e.g. `SIZE`

= `U8`

-> type of internal counter is `u8`

, etc. `See here`

.

I tried writing a type function (i.e. a trait) call `CalcMinUIntType<V: Unsigned + NonZero, B: ...>`

(see Playground link later) but it gives me the StackOverflow error at compile time, meaning the evaluation of the type level recursion does not end.

Here is my implementation of the trait (`Playground`

).

I need to constrain `B`

to be 'at least `U8`

and at most `U64`

' to have the base cases but I am not sure how to do it at the type level, lol.

Implementation pasted below for convenience:

```
/*
[dependencies]
typenum = "1.17.0"
*/
#![recursion_limit = "4000"]
fn main() {
use core::{
marker::PhantomData,
ops::{Add, Shl},
};
use typenum::{
consts::{U0, U1, U16, U2, U254, U32, U365, U64, U66, U8},
Bit, False, IsGreaterOrEqual, IsLess, IsLessOrEqual, NonZero, PowerOfTwo, Prod, Sum, True,
Unsigned,
};
trait If<Cond: Bit> {
type Outcome;
}
trait MinimallyRepresentableAsUInt:
Unsigned
+ NonZero
+ IsLessOrEqual<U64, Output = True>
+ IsGreaterOrEqual<U8, Output = True>
+ PowerOfTwo
{
}
impl MinimallyRepresentableAsUInt for U8 {}
impl MinimallyRepresentableAsUInt for U16 {}
impl MinimallyRepresentableAsUInt for U32 {}
impl MinimallyRepresentableAsUInt for U64 {}
struct Either<L: Unsigned + NonZero, R: MinimallyRepresentableAsUInt>(PhantomData<(L, R)>);
impl<L: Unsigned + NonZero, R: MinimallyRepresentableAsUInt> If<False> for Either<L, R> {
type Outcome = L;
}
impl<L: Unsigned + NonZero, R: MinimallyRepresentableAsUInt> If<True> for Either<L, R> {
type Outcome = R;
}
trait CalcMinUIntType<V: Unsigned + NonZero, B: MinimallyRepresentableAsUInt> {
type Outcome: MinimallyRepresentableAsUInt;
}
type U1LeftShift<Bits> = <U1 as Shl<Bits>>::Output;
// println!("{:?}", U1LeftShift::<U16>::USIZE); // OK
// println!("{:?}", Prod::<U8, U2>::USIZE); // OK
// type MinUIntType = <() as CalcMinUIntType<V, B>>::Outcome
// println!("{:?}", <U66 as IsLess<U1LeftShift<U8>>>::Output::BOOL); // OK
// impl<V: Unsigned + NonZero> CalcMinUIntType<V, U64> for () {
// type Outcome = U64;
// }
impl<V: Unsigned + NonZero, B: MinimallyRepresentableAsUInt> CalcMinUIntType<V, B> for () {
type Outcome = <Either<<() as CalcMinUIntType<V, Prod<B, U2>>>::Outcome, B> as If<
<V as IsLess<U1LeftShift<B>>>::Output,
>>::Outcome;
}
}
```

The type level function is modeled after the following runtime function given by ChatGPT, of course, when bits = 0, it will recurse forever and when value is larger than `u64::MAX`

it might overflow if your pointer width is 64 bits (or rather whenever the value is larger than your CPU pointer width, it overflows or wrapped in released mode).

```
fn min_unsigned_type(value: usize, bits: usize) -> usize {
if value < (1 << bits) {
bits
} else {
min_unsigned_type(value, bits * 2)
}
}
```