Associated constants (I think)

Hi, I'm trying to do the following:

struct Buffer<const BITS: usize> {
}
impl<const BITS: usize> Buffer<BITS> {
    const ADDRESS_BITS: usize = BITS * 2; // < Some math (hopefully log2 but that may require int_log :) )
    pub fn new() -> Self {
        let x = Input::<BITS>::new();
        let y = Input::<ADDRESS_BITS>::new();

The error I get is "unresolved item provided when a constant was expected" and rustc asks me to change to { ADDRESS_BITS } but then I get further errors.

I did search but I'm not sure if what I want to do is possible. Is there a way to do some math on a constant parameter and pass it to another generic as a parameter?

Thanks for your help!

I tried a few ways, I think what you’re trying might not be possible in current stable rust. On nightly, using unstable features, something like the following does work

#![feature(generic_const_exprs)]

struct Input<const BITS: usize> {}
impl<const BITS: usize> Input<BITS> {
    fn new() -> Self {
        Self {}
    }
}

struct Buffer<const BITS: usize> {}

impl<const BITS: usize> Buffer<BITS> {
    const ADDRESS_BITS: usize = BITS * 2;
    pub fn new() -> Self
    where
        [(); Self::ADDRESS_BITS]:, // <- this bound basically (implicitly) just
        // requires the caller to check that Self::ADDRESS_BITS is well-formed 
        // (which it isn’t for arge values of BITS, because BITS*2 can overflow)
    {
        let x = Input::<BITS>::new();
        let y = Input::<{ Self::ADDRESS_BITS }>::new();
        todo!()
    }
}

See also

https://github.com/rust-lang/rust/issues/76560

and

2 Likes

Thank-you! I needed to modify your solution a little since I had the types as members of the struct but your answer was what I needed and you even added the design for what it might look like in stable. Thanks again :smiley:

#![feature(generic_const_exprs)]

const fn foo(n: usize) -> usize {
    n * 2
}

struct Input<const BITS: usize> {}
impl<const BITS: usize> Input<BITS> {
    fn new() -> Self {
        Self {}
    }
}

struct Buffer<const BITS: usize>
    where
        [(); foo(BITS)]: {
    x: Input::<BITS>,
    y: Input::<{ foo(BITS) }>
}

impl<const BITS: usize> Buffer<BITS>
    where
        [(); foo(BITS)]: {
    pub fn new() -> Self
    {
        let x = Input::<BITS>::new();
        let y = Input::<{ foo(BITS) }>::new();
        todo!()
    }
}

Depending on your use-case for the BITS const generic parameter, it might be possible to use typenum args instead; those would offer more flexibility on stable, including support for more involved calculations like multiplication or even logarithms. E.g. for use as array lengths, there’s types like GenericArray.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.