This question already has answers here:
How to get a slice as an array in Rust?
(7 answers)
Closed 6 years ago.
I have a structure with some fixed-sized arrays:
struct PublicHeaderBlock_LAS14 {
file_signature: [u8; 4],
file_source_id: u16,
global_encoding: u16,
project_id_data_1: u32,
project_id_data_2: u16,
project_id_data_3: u16,
project_id_data_4: [u8; 8],
version_major: u8,
version_minor: u8,
systemIdentifier: [u8; 32], // ...
}
I'm reading in bytes from a file into a fixed size array and am copying those bytes into the struct bit by bit.
fn create_header_struct_las14(&self, buff: &[u8; 373]) -> PublicHeaderBlock_LAS14 {
PublicHeaderBlock_LAS14 {
file_signature: [buff[0], buff[1], buff[2], buff[3]],
file_source_id: (buff[4] | buff[5] << 7) as u16,
global_encoding: (buff[6] | buff[7] << 7) as u16,
project_id_data_1: (buff[8] | buff[9] << 7 | buff[10] << 7 | buff[11] << 7) as u32,
project_id_data_2: (buff[12] | buff[13] << 7) as u16,
project_id_data_3: (buff[14] | buff[15] << 7) as u16,
project_id_data_4: [buff[16], buff[17], buff[18], buff[19], buff[20], buff[21], buff[22], buff[23]],
version_major: buff[24],
version_minor: buff[25],
systemIdentifier: buff[26..58]
}
}
The last line (systemIdentifier) doesn't work, because in the struct it is a [u8; 32] and buff[26..58] is a slice. Can I return convert a slice to a fixed sized array like that over a range, instead of doing what I've done to say file_signature?
Edit: Since Rust 1.34, you can use TryInto, which is derived from TryFrom<&[T]> for [T; N]
struct Foo {
arr: [u8; 32],
}
fn fill(s: &[u8; 373]) -> Foo {
// We unwrap here because it will always return `Ok` variant
let arr: [u8; 32] = s[26..68].try_into().unwrap();
Foo { arr }
}
Original answer from 2016:
There is no safe way to initialize an array in a struct with a slice. You need either resort to unsafe block that operates directly on uninitialized memory, or use one of the following two initialize-then-mutate strategies:
Construct an desired array, then use it to initialize the struct.
struct Foo {
arr: [u8; 32],
}
fn fill(s: &[u8; 373]) -> Foo {
let mut a: [u8; 32] = Default::default();
a.copy_from_slice(&s[26..58]);
Foo { arr: a }
}
Or initialize the struct, then mutate the array inside the struct.
#[derive(Default)]
struct Foo {
arr: [u8; 32],
}
fn fill(s: &[u8; 373]) -> Foo {
let mut f: Foo = Default::default();
f.arr.copy_from_slice(&s[26..58]);
f
}
The first one is cleaner if your struct has many members. The second one may be a little faster if the compiler cannot optimize out the intermediate copy. But you probably will use the unsafe method if this is the performance bottleneck of your program.
Thanks to #malbarbo we can use this helper function:
use std::convert::AsMut;
fn clone_into_array<A, T>(slice: &[T]) -> A
where A: Sized + Default + AsMut<[T]>,
T: Clone
{
let mut a = Default::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
to get a much neater syntax:
fn main() {
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let e = Example {
a: clone_into_array(&original[0..4]),
b: clone_into_array(&original[4..10]),
};
println!("{:?}", e);
}
as long as T: Default + Clone.
It will panic! if the target array and the passed-in slice do not have the same length, because clone_from_slice does.
Related
I'm having trouble initializing a fixed length array. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:
#[derive(Debug)]
struct Foo { a: u32, b: u32 }
impl Default for Foo {
fn default() -> Foo { Foo{a:1, b:2} }
}
pub fn main() {
let mut foo_array: [Foo; 10];
// Do something here to in-place initialize foo_array?
for f in foo_array.iter() {
println!("{:?}", f);
}
}
error[E0381]: use of possibly uninitialized variable: `foo_array`
--> src/main.rs:13:14
|
13 | for f in foo_array.iter() {
| ^^^^^^^^^ use of possibly uninitialized `foo_array`
I implemented the Default trait, but Rust does not seem to call this by default akin to a C++ constructor.
What is the proper way to initialize a fixed length array? I'd like to do an efficient in-place initialization rather than some sort of copy.
Related: Why is the Copy trait needed for default (struct valued) array initialization?
Related: Is there a way to not have to initialize arrays twice?
The safe but somewhat inefficient solution:
#[derive(Copy, Clone, Debug)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Since you're specifically asking for a solution without copies:
use std::mem::MaybeUninit;
#[derive(Debug)]
struct Foo {
a: u32,
b: u32,
}
// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
fn drop(&mut self) {
println!("Destructor running for a Foo");
}
}
pub fn main() {
let array = {
// Create an array of uninitialized values.
let mut array: [MaybeUninit<Foo>; 10] = unsafe { MaybeUninit::uninit().assume_init() };
for (i, element) in array.iter_mut().enumerate() {
let foo = Foo { a: i as u32, b: 0 };
*element = MaybeUninit::new(foo);
}
unsafe { std::mem::transmute::<_, [Foo; 10]>(array) }
};
for element in array.iter() {
println!("{:?}", element);
}
}
This is recommended by the documentation of MaybeUninit.
You can use the arrayvec crate:
Cargo.toml
[package]
name = "initialize_array"
version = "0.1.0"
edition = "2018"
[dependencies]
arrayvec = "0.7.2"
src/main.rs
use arrayvec::ArrayVec;
use std::iter;
#[derive(Clone)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
.take(10)
.collect::<ArrayVec<_, 10>>()
.into_inner()
.unwrap_or_else(|_| unreachable!());
}
The easiest way is to derive Copy on your type and initialize the array with that, copying the element N times:
#[derive(Copy)]
struct Foo {
a: u32,
b: u32,
}
let mut foo_array = [Foo { a: 1, b: 2 }; 10];
If you want to avoid copying, there are a couple options. You can use the Default trait:
let mut foo_array: [Foo; 10] = Default::default();
However, this is limited to arrays up to 32 elements. With const generics, it is now possible for the standard library to provide Default for all arrays. However, this would be a backward incompatible change for subtle reasons that are being worked on.
For now, you can take advantage of the fact that const values are also allowed in array repetition expressions:
const FOO: Foo = Foo { a: 1, b: 2 };
let mut foo_array = [FOO; 10];
If you're on nightly, you can use array::map:
#![feature(array_map)]
let mut foo_array = [(); 10].map(|_| Foo::default())
I have an array of an unknown size, and I would like to get a slice of that array and convert it to a statically sized array:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // expected array `[u8; 3]`, found slice `[u8]`
}
How would I do this?
You can easily do this with the TryInto trait (which was stabilized in Rust 1.34):
// Before Rust 2021, you need to import the trait:
// use std::convert::TryInto;
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
But even better: there is no need to clone/copy your elements! It is actually possible to get a &[u8; 3] from a &[u8]:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
As mentioned in the other answers, you probably don't want to panic if the length of barry is not 3, but instead handle this error gracefully.
This works thanks to these impls of the related trait TryFrom (before Rust 1.47, these only existed for arrays up to length 32):
impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N]
where
T: Copy,
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
Thanks to #malbarbo we can use this helper function:
use std::convert::AsMut;
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
to get a much neater syntax:
fn main() {
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let e = Example {
a: clone_into_array(&original[0..4]),
b: clone_into_array(&original[4..10]),
};
println!("{:?}", e);
}
as long as T: Default + Clone.
If you know your type implements Copy, you can use this form:
use std::convert::AsMut;
fn copy_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Copy,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
a
}
Both variants will panic! if the target array and the passed-in slice do not have the same length.
I recommend using the crate arrayref, which has a handy macro for doing just this.
Note that, using this crate, you create a reference to an array, &[u8; 3], because it doesn't clone any data!
If you do want to clone the data, then you can still use the macro, but call clone at the end:
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> &[u8; 3] {
array_ref!(barry, 0, 3)
}
or
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> [u8; 3] {
array_ref!(barry, 0, 3).clone()
}
You can manually create the array and return it.
Here is a function that can easily scale if you want to get more (or less) than 3 elements.
Note that if the slice is too small, the end terms of the array will be 0's.
fn pop(barry: &[u8]) -> [u8; 3] {
let mut array = [0u8; 3];
for (&x, p) in barry.iter().zip(array.iter_mut()) {
*p = x;
}
array
}
Here's a function that matches the type signature you asked for.
fn pop(barry: &[u8]) -> [u8; 3] {
[barry[0], barry[1], barry[2]]
}
But since barry could have fewer than three elements, you may want to return an Option<[u8; 3]> rather than a [u8; 3].
fn pop(barry: &[u8]) -> Option<[u8; 3]> {
if barry.len() < 3 {
None
} else {
Some([barry[0], barry[1], barry[2]])
}
}
I was unhappy with other answers because I needed several functions that return varying length fixed u8 arrays. I wrote a macro that produces functions specific for the task. Hope it helps someone.
#[macro_export]
macro_rules! vec_arr_func {
($name:ident, $type:ty, $size:expr) => {
pub fn $name(data: std::vec::Vec<$type>) -> [$type; $size] {
let mut arr = [0; $size];
arr.copy_from_slice(&data[0..$size]);
arr
}
};
}
//usage - pass in a name for the fn, type of array, length
vec_arr_func!(v32, u8, 32);
v32(data); //where data is std::vec::Vec<u8>
The nice common thing between Vec, 'Slice' and Array is Iter, so you can zip and map both together, as simple as:
let x = vec![1, 2, 3];
let mut y: [u8; 3] = [Default::default(); 3];
println!("y at startup: {:?}", y);
x.iter().zip(y.iter_mut()).map(|(&x, y)| *y = x).count();
println!("y copied from vec: {:?}", y);
This is as the array is 1 dimensional array.
To test all together, vec, slice and array, here you go:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![Default::default(); 3];
println!("X at startup: {:?}", x);
slice.iter().zip(x.iter_mut()).map(|(&s, x)| *x = s).count();
println!("X copied from vec: {:?}", x);
Another option which should be faster than byte-by-byte copy is:
y[..x.len()].copy_from_slice(&x);
Which is applicable for all, below is example:
let a = [1, 2, 3, 4, 5];
let mut b: Vec<u8> = vec![Default::default(); 5];
b[..a.len()].copy_from_slice(&a);
println!("Copy array a into vector b: {:?}", b);
let x: Vec<u8> = vec![1, 2, 3, 4, 5];
let mut y: [u8; 5] = [Default::default(); 5];
y[..x.len()].copy_from_slice(&x);
println!("Copy vector x into array y: {:?}", y);
I want to get the size of all dimensions of an array in Rust but I'm not sure how to go about this. I'm able to get the length of the array using x.len() but I need to somehow do this recursively.
I want to be able to do something like this:
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
// [2, 3]
A slice with a shape like [[1], [2, 3], [4, 5, 6]] should give an error.
It's not possible to do this in a generic fashion for every possible depth of nesting. Rust is a statically typed language, so you have to know your input and output types. What is an input type for [1] and what is the input type for [[1]]? Likewise, what are the corresponding output types?
The closest I know of is a trait with an associated type. This allows implementing it for a specific type which then associates another output type:
trait Thing {
type Dimensions;
fn thing(self) -> Self::Dimensions;
}
However, as soon as you implement it, you run into problems:
impl<'a, T> Thing for &'a[T] {
type Dimensions = usize;
fn thing(self) -> usize {
self.len()
}
}
impl<'a, T> Thing for &'a[&'a[T]] {
type Dimensions = [usize; 2];
fn thing(self) -> Self::Dimensions {
[self.len(), self[0].len()]
}
}
error[E0119]: conflicting implementations of trait `Thing` for type `&[&[_]]`:
--> src/main.rs:14:1
|
6 | impl<'a, T> Thing for &'a[T] {
| - first implementation here
...
14 | impl<'a, T> Thing for &'a[&'a[T]] {
| ^ conflicting implementation for `&[&[_]]`
That's because a &[[T]] is a &[T].
You may also think to try something recursive, but there's no way to say &[T] and know if T can be further iterated or not. If you had an HasLength trait and a DoesntHaveLength trait, nothing stops you from implementing both traits for a single type. Thus, you are stopped again.
Here's one partial attempt at using specialization:
#![feature(specialization)]
trait Dimensions: Sized {
fn dimensions(self) -> Vec<usize> {
let mut answers = vec![];
self.dimensions_core(&mut answers);
answers
}
fn dimensions_core(self, &mut Vec<usize>);
}
impl<'a, T> Dimensions for &'a [T] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
}
}
impl<'a, T> Dimensions for &'a [T]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 2] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2)
}
}
impl<'a, T> Dimensions for [T; 2]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2);
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 3] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3)
}
}
impl<'a, T> Dimensions for [T; 3]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3);
self[0].dimensions_core(answers);
}
}
// Also implement for all the other sizes of array as well as `Vec`
fn main() {
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
let x = [[1, 2], [3, 4], [5, 6]];
println!("{:?}", x.dimensions());
}
It has the obvious downside that you still have to implement the trait for each array size in order to get specialization to kick in.
I'm guessing that you are coming from a language that is highly dynamic. Different languages have different strengths and weaknesses. In Rust, you know your input types, so there's no way the function wouldn't know the nesting of my type. If it's going to receive a Vec<T> or a Vec<&[Vec<T>]>, I will know the depth of nesting ahead of time, so I can write a function that returns the lengths of each one:
fn depth3<A, B, C, T>(a: A) -> [usize; 3]
where A: AsRef<[B]>,
B: AsRef<[C]>,
C: AsRef<[T]>
{
let a = a.as_ref();
// All of these should check that the length is > 1
// and possibly that all children have same length
let b = a[0].as_ref();
let c = b[0].as_ref();
[a.len(), b.len(), c.len()]
}
fn main() {
let x = [[[1], [2], [3]], [[4], [5], [6]]];
println!("{:?}", depth3(&x));
}
This function is as generic as I think it can be - you pass in references to arrays, slices, vectors, or direct values for those types. In fact, I can't think of a way to even define a slice/vector/array with an unknown depth. I think to do something like that you'd have to introduce some new type (likely an enum) with some indirection so that you could have a non-infinite size.
An array is defined as [T], T can't be both [U; 2] and [U; 3]. This means that you wouldn't even be able to get past compilation with this.
If you instead used a Vec<Vec<T>> as #Shepmaster hints, you could do something like this.
fn main() {
let x = vec![vec![1, 2, 3], vec![4, 5]];
println!("{:?}", get_2d_dimension(&x));
}
fn get_2d_dimension<T>(arr: &[Vec<T>]) -> Result<(usize, usize), &str> {
let rows = arr.len();
if rows <= 1 {
return Err("Not 2d");
}
let cols = arr[0].len();
if arr.iter().skip(1).filter(|v| v.len() == cols).count() != rows - 1 {
Err("Not square.")
} else {
Ok((rows, cols))
}
}
As others have noted, finding the dimensions of a "vanilla" nested list is impossible. However, you can choose to implement a custom nested list data structure, like so:
#[derive(Clone, Debug)]
pub enum NestedList<S>
where S: Clone
{
Integer(S),
Array(Vec<NestedList<S>>)
}
Then you'd have to rewrite your nested list using NestedList:
use NestedList::Integer as i;
use NestedList::Array as a;
fn main() {
let array = a(vec![
a(vec![i(1), i(2), i(3)]),
a(vec![i(4), i(5), i(6)])
]);
}
from which you can find the dimensions. Here is an implementation of this method. It is very verbose, but I hope this is what you were looking for?
I'm reading a series of bytes from a socket and I need to put each segment of n bytes as a item in a struct.
use std::mem;
#[derive(Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things;
unsafe {
foobar = mem::transmute::<[u8; 3], Things>(array);
}
println!("{:?}", foobar);
}
I'm getting errors that say that foobar is 32 bits when array is 24 bits. Shouldn't foobar be 24 bits (8 + 16 = 24)?
The issue here is that the y field is 16-bit-aligned. So your memory layout is actually
x
padding
y
y
Note that swapping the order of x and y doesn't help, because Rust's memory layout for structs is actually undefined (and thus still 32 bits for no reason but simplicity in the compiler). If you depend on it you will get undefined behavior.
The reasons for alignment are explained in Purpose of memory alignment.
You can prevent alignment from happening by adding the attribute repr(packed) to your struct, but you'll lose performance and the ability to take references of fields:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
The best way would be to not use transmute at all, but to extract the values manually and hope the optimizer makes it fast:
let foobar = Things {
x: array[0],
y: ((array[1] as u16) << 8) | (array[2] as u16),
};
A crate like byteorder may simplify the process of reading different sizes and endianness from the bytes.
bincode and serde can do this quit simply.
use bincode::{deserialize};
use serde::{Deserialize};
#[derive(Deserialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things = deserialize(&array).unwrap();
println!("{:?}", foobar);
}
This also works well for serializing a struct into bytes as well.
use bincode::{serialize};
use serde::{Serialize};
#[derive(Serialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let things = Things{
x: 22,
y: 8780,
};
let baz = serialize(&things).unwrap();
println!("{:?}", baz);
}
I was having issues using the byteorder crate when dealing with structs that also had char arrays. I couldn't get past the compiler errors. I ended up casting like this:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let data: [u8; 3] = [0x22, 0x76, 0x34];
unsafe {
let things_p: *const Things = data.as_ptr() as *const Things;
let things: &Things = &*things_p;
println!("{:x} {:x}", things.x, things.y);
}
}
Note that with using packed, you get this warning:
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
If you can, change Things to behave like a C struct:
#[repr(C)]
struct Things2 {
x: u8,
y: u16,
}
Then initialize data like this. Note the extra byte for alignment purposes.
let data: [u8; 4] = [0x22, 0, 0x76, 0x34];
use std::mem;
fn main() {
let bytes = vec!(0u8, 1u8,2u8, 3, 4, 5, 6, 7, 8, 9, 0xffu8, );
let data_ptr: *const u64 = unsafe { mem::transmute(bytes[0..4].as_ptr()) };
let data: u64 = unsafe { *data_ptr };
println!("{:#x}", data);
}
I'm reading a series of bytes from a socket and I need to put each segment of n bytes as a item in a struct.
use std::mem;
#[derive(Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things;
unsafe {
foobar = mem::transmute::<[u8; 3], Things>(array);
}
println!("{:?}", foobar);
}
I'm getting errors that say that foobar is 32 bits when array is 24 bits. Shouldn't foobar be 24 bits (8 + 16 = 24)?
The issue here is that the y field is 16-bit-aligned. So your memory layout is actually
x
padding
y
y
Note that swapping the order of x and y doesn't help, because Rust's memory layout for structs is actually undefined (and thus still 32 bits for no reason but simplicity in the compiler). If you depend on it you will get undefined behavior.
The reasons for alignment are explained in Purpose of memory alignment.
You can prevent alignment from happening by adding the attribute repr(packed) to your struct, but you'll lose performance and the ability to take references of fields:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
The best way would be to not use transmute at all, but to extract the values manually and hope the optimizer makes it fast:
let foobar = Things {
x: array[0],
y: ((array[1] as u16) << 8) | (array[2] as u16),
};
A crate like byteorder may simplify the process of reading different sizes and endianness from the bytes.
bincode and serde can do this quit simply.
use bincode::{deserialize};
use serde::{Deserialize};
#[derive(Deserialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things = deserialize(&array).unwrap();
println!("{:?}", foobar);
}
This also works well for serializing a struct into bytes as well.
use bincode::{serialize};
use serde::{Serialize};
#[derive(Serialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let things = Things{
x: 22,
y: 8780,
};
let baz = serialize(&things).unwrap();
println!("{:?}", baz);
}
I was having issues using the byteorder crate when dealing with structs that also had char arrays. I couldn't get past the compiler errors. I ended up casting like this:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let data: [u8; 3] = [0x22, 0x76, 0x34];
unsafe {
let things_p: *const Things = data.as_ptr() as *const Things;
let things: &Things = &*things_p;
println!("{:x} {:x}", things.x, things.y);
}
}
Note that with using packed, you get this warning:
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
If you can, change Things to behave like a C struct:
#[repr(C)]
struct Things2 {
x: u8,
y: u16,
}
Then initialize data like this. Note the extra byte for alignment purposes.
let data: [u8; 4] = [0x22, 0, 0x76, 0x34];
use std::mem;
fn main() {
let bytes = vec!(0u8, 1u8,2u8, 3, 4, 5, 6, 7, 8, 9, 0xffu8, );
let data_ptr: *const u64 = unsafe { mem::transmute(bytes[0..4].as_ptr()) };
let data: u64 = unsafe { *data_ptr };
println!("{:#x}", data);
}