3

How do I create a byte slice constant in rust, something as follows?

// This does not compile, but just to show my intention.
pub const MyConst: &'static [u8; 256] = b"abcdef" + [0u8; 250];

// Basically, the value is b"abcdef00000...", the `000...` appended at the end 
// are a series of byte 0, not character 0.
Jimmy Chu
  • 972
  • 8
  • 27
  • You can do this using const functions, or alternatively write the constant out by hand: `b"abcdef\0\0\0\0\0\0\0\0..."`. More context would be helpful here as to why you need it. – Richard Matheson Jul 18 '20 at 10:10
  • I'm not sure that there are const functions that can work with `[u8; 256]`. I think you have to write this by hand. If it could be a `static` instead of a `const` then there are more options (like `lazy_static`). – Peter Hall Jul 18 '20 at 10:12

3 Answers3

5

You can use a const fn to create your array:

const fn foo() -> [u8; 256] {
    let mut a = [0; 256];
    a[0] = b'a';
    a[1] = b'b';
    a[2] = b'c';
    a[3] = b'd';
    a[4] = b'e';
    a[5] = b'f';
    a
}

const FOO: [u8; 256] = foo();

fn main() {
    println!("{:?}", &FOO[0..10]);
}

Note that const fn are still pretty limited, so to my knowledge, you can't do any better than the sequence of a[i] = b at the moment.

mcarton
  • 27,633
  • 5
  • 85
  • 95
4

There currently isn't a feature in the language nor in the standard library for combining multiple byte arrays together into a single slice at compile time. There happens to be a pending RFC proposing an extension to the concat! macro, which currently only works for string literals. There are no guarantees that it will ever be approved, though.

A few alternative solutions follow.

  1. Make a UTF-8 string and call as_bytes(). As a string slice however, it won't be possible to include certain character combinations or write a compact representation of [0u8; 250].
pub const BYTES: &[u8] = concat!("abcdef", "\0\0\0\0\0\0\0\0\0\0").as_bytes();
  1. Some crates may claim to provide the solution that you are looking for. See proc_concat_bytes, for example:
use proc_concat_bytes::concat_bytes;
let c_str  = &concat_bytes!(b"Hello World!", b'\0')[..]).unwrap();
  1. Write the bytes to a file, then use include_bytes!.
const BYTES: &[u8; 258] = include_bytes!("bytes.bin");
  1. Enter before-main land and construct a static vector with lazy_static!. We would then have a vector constructed by the program, but should fulfil the intended requirements once built.
use lazy_static::lazy_static;

lazy_static! {
    static ref BYTES: Vec<u8> = {
        let mut data = b"abcdefg".to_vec();
        data.extend(&[0u8; 250][..]);
        data
    };
}

See also:

E_net4
  • 27,810
  • 13
  • 101
  • 139
2

On recent nightly compilers, you can now use the unstable concat_bytes! macro to do this:

#![feature(concat_bytes)]
pub const MY_CONST: &[u8; 256] = concat_bytes!(b"abcdef", [0; 250]);
smitop
  • 4,770
  • 2
  • 20
  • 53