Const function to get fixed size array?

I have 3rd party function that return fixed size array:

//other 3rd party
fn f1() -> [u8; X] { .. }

I want to create buffer of the same length without heap allocation,
and without introducing constants is it possible?

Pseudo code:

let tx_buf = f1();
let mut rx_buf = [0u8; tx_buf.len()];

But len is not const function, so this doesn't compile.
I do not want to introduce const just for one call:

const N: usize = X;
let tx_buf: [u8; N] = f1();
let mut rx_buf = [0u8; tx_buf.len()];

So may be there is some kind of trait to get fixed array size during compilation?

There is no general way to get the size of an array at compile time. If there is just 1 call, then you can fill in the length manually

There is one call of f1, but there are also f2, f3 and so on. All of them return different fixed sized arrays. So I end up something like const N1, const N2... what is not nice.

The first thing that I think about is

trait FixedArrayLen {
    const VALUE: usize;
}

impl FixedArrayLen for [u8; 1] {
    const VALUE: usize = 1;
}

impl FixedArrayLen for [u8; 2] {
    const VALUE: usize = 2;
}

but I can not get assotiated VALUE for variable.
I can use size_of_val, but it doesn't marked as const: Make size_of_val a const fn (and stabilize it as such) · Issue #46571 · rust-lang/rust · GitHub

You can't, because it will eventually run into something like this error (playground)

error[E0435]: attempt to use a non-constant value in a constant
 --> src/lib.rs:8:47
  |
8 |     let rx_buf = [0; size_of_array::<i32, _>(&tx_buf)];
  |                                               ^^^^^^ non-constant value
pub const fn size_of_array<T, A>(array: &A) -> usize {
    std::mem::size_of::<A>() / std::mem::size_of::<T>()
}

I guess another way to do this would be

let tx_buf = ...;
let mut rx_buf = tx_buf; // copy the array
rx_buf.iter_mut().for_each(|x| *x = 0); // zero out rx_buf if needed

This way you never need to explicitly deal with the length of the array. The zeroing will be lowered to a memset at worst, so it's not that bad.

3 Likes

You can do something like this, but it's nightly-only and it doesn't generalize well to functions with different numbers of parameters:

#![feature(const_fn)]

const fn return_size<T, F: Fn() -> T>(f: &F) -> usize {
    std::mem::size_of::<T>()
}

let tx_buf = foo();
let rx_buf = [0u8; return_size(&foo)];

(Really what we want here are const generics.)

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.