Stable workarounds for `<const N: usize>` -> 2N?

On Rust stable, is there some clever trick work around where given generic parameter

const N: usize

we can pass a generic parameter 2*N or N+N ?

My guess is no, but if you need it to create an array of length 2n, there may be other alternatives available. For example:

use core::ops::{Deref, DerefMut};

struct DoubleArray<const N: usize, T> {
    inner: [[T; N]; 2],
}

impl<const N: usize, T> Deref for DoubleArray<N, T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        let inner_ptr = self.inner.as_ptr() as *const T;
        let len = 2*N;
        unsafe {
            std::slice::from_raw_parts(inner_ptr, len)
        }
    }
}

impl<const N: usize, T> DerefMut for DoubleArray<N, T> {
    fn deref_mut(&mut self) -> &mut [T] {
        let inner_ptr = self.inner.as_mut_ptr() as *mut T;
        let len = 2*N;
        unsafe {
            std::slice::from_raw_parts_mut(inner_ptr, len)
        }
    }
}
2 Likes

This is my fault for not being clear. I need more than an array, I need the actual value 2n. I have something like:

pub struct Image<const N: usize> {
  data: Vec<...>;
}

then I have types like:

Image<512>,
Image<256>,
Image<16>,

which comes in handy when having to deal with textures.

It’s a bit hard to offer specific solution without looking into what specifically are you doing, but one option is to pass two params, M and N, and check that 2N = M.

struct AssertEqSum<const S: usize, const A: usize, const B: usize>;
impl<const S: usize, const A: usize, const B: usize> AssertEqSum<S, A, B> {
    const OK: () = [()][A + B - S];
}

is another way to do this:

const _: usize = EXPR1 - EXPR2;
const _: usize = EXPR2 - EXPR1;

this can work only when the two are equal.

===

To play devil's advocate, what prevents the compiler from optimizing these out ?

It's done as part of type checking. That can't be optimized away β€” only runtime things can be optimized.

1 Like