Best Way To Mutate Arrays in Structs? - arrays

I have a struct like the following
struct Foo {
x: [i8;64]
y: i8
}
And I want to update a value inside array x in Foo when I pass it through a function. The best solution I can come up with is make a mutable copy of x and then update that copy, and then create a new Foo with the new array.
fn updateFoo(myFoo: Foo, index: usize, newvalue: i8) -> Foo {
let mut newX = myFoo.x;
newX[index] = newvalue;
Foo {
x: newX,
y: myFoo.y,
}
}
Is this an efficient and idiomatic way of mutating arrays within a struct in Rust? What alternatives are there for me to update values inside of an array inside Rust? Thank you for your help.

You can also just pass in a mutable ref to Foo:
struct Foo {
x: [i8; 64],
y: i8,
}
fn updateFoo(myFoo: &mut Foo, index: usize, newvalue: i8) {
myFoo.x[index] = newvalue;
}
playground

Related

Cannot borrow as mutable more than once at a time in asynchronous code with a loop

What is causing multiple simultaneous mutable borrows in this code? I suspect it has to do with the <'a> declared on the type F because if I remove the 'a from the struct I am able to write the loop just fine.
This works, but this does not:
struct F<'a> {
i: u32,
a: &'a mut u32,
}
impl<'a> F<'a> {
async fn looper(self, x: &'a mut u32) -> F<'a> {
let mut this = Some(self);
loop {
let me = this.take().unwrap();
let new_me = me.inner(x).await;
this.replace(new_me);
}
}
async fn inner(self, x: &'a mut u32) -> F<'a> {
*x += self.i;
self
}
}
playground
error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> src/lib.rs:12:35
|
12 | let new_me = me.inner(x).await;
| ^ mutable borrow starts here in previous iteration of loop

How to initialize an array with an iterator in Rust? [duplicate]

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())

How to reset all array elements?

This is the shortest I came up with, after extensive googling and studying the sources:
let mut buf = [0u8; 200];
for elem in buf.iter_mut() {
*elem = 0;
}
Is there really no way to make this a one-liner, like buf.set_all(0)?
Is there really no way to make this a one-liner, like buf.set_all(0)?
Sure you can make it a one-liner...
for elem in buf.iter_mut() { *elem = 0; }
Okay, okay... if you do this a lot, you can define an extension trait that provides a set_all method.
trait SetAll {
type Elem;
fn set_all(&mut self, value: Self::Elem);
}
impl<T> SetAll for [T] where T: Clone {
type Elem = T;
fn set_all(&mut self, value: T) {
for e in self {
*e = value.clone();
}
}
}
But in terms of just using what's in the standard library, there's for_each (as noted by Sven Marnach):
buf.iter_mut().for_each(|x| *x = 0)
You could simply construct a new array and move it into the array you want to change.
buf = [0u8; 200];
If the compiler is decent, it can optimize out the temporary array and write directly to the target.
in your scene, this is my solution:
let mut buf = [1u8; 200];
unsafe {
std::ptr::write_volatile(&mut buf, [0u8;200]);
}
Is there really no way to make this a one-liner, like buf.set_all(0)?
and you also can do like this:
struct Buf([u8;200]);
impl Buf {
fn clear(&mut self) {
unsafe {
std::ptr::write_volatile(&mut self.0, [0u8;200]);
}
}
}
fn main() {
let mut buf1 = Buf([1u8; 200]);
let mut buf2 = Buf([2u8; 200]);
buf1.clear();
buf2.clear();
println!("{}, {}", buf1.0[199], buf2.0[0]);
}

How to extract a usize bytes and return them? [duplicate]

I want to create array like this:
let arr = [0; length];
Where length is a usize. But I get this error
E0307
The length of an array is part of its type. For this reason, this length
must be a compile-time constant.
Is it possible to create array with dynamic length? I want an array, not a Vec.
Is it possible to create array with dynamic length?
No. By definition, arrays have a length defined at compile time. A variable (because it can vary) is not known at compile time. The compiler would not know how much space to allocate on the stack to provide storage for the array.
You will need to use a Vec:
let arr = vec![0; length];
See also:
Is it possible to control the size of an array using the type parameter of a generic?
This should be possible after variable length arrays (VLA) are implemented.
You can create your own HeapArray. It's not that complicated if you read alloc's docs:
use std::alloc::{alloc, dealloc, Layout};
pub struct HeapArray<T> {
ptr: *mut T,
len: usize,
}
impl<T> HeapArray<T> {
pub fn new(len: usize) -> Self {
let ptr = unsafe {
let layout = Layout::from_size_align_unchecked(len, std::mem::size_of::<T>());
alloc(layout) as *mut T
};
Self { ptr, len }
}
pub fn get(&self, idx: usize) -> Option<&T> {
if idx < self.len {
unsafe { Some(&*(self.ptr.add(idx))) }
} else {
None
}
}
pub fn get_mut(&self, idx: usize) -> Option<&mut T> {
if idx < self.len {
unsafe { Some(&mut *(self.ptr.add(idx))) }
} else {
None
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<T> Drop for HeapArray<T> {
fn drop(&mut self) {
unsafe {
dealloc(
self.ptr as *mut u8,
Layout::from_size_align_unchecked(self.len, std::mem::size_of::<T>()),
)
};
}
}
impl<T> std::ops::Index<usize> for HeapArray<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).unwrap()
}
}
impl<T> std::ops::IndexMut<usize> for HeapArray<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}
You may also add methods like as_slice, get_unchecked, etc.

How can I initialize an array using a function? [duplicate]

This question already has answers here:
Initialize a large, fixed-size array with non-Copy types
(8 answers)
Closed last month.
I want to create an array of 10 empty vectors in Rust, but [Vec::new(); 10] doesn't work as Vec doesn't implement Copy. How can I do this, and in more general terms how can I initialize a array by repeatedly calling a function?
As of Rust 1.55.0, Sep 2021
You can use array's .map() method for general functions:
let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
(With Rust 1.63.0, Aug 2022 consider using from_fn).
As of Rust 1.63
Use from_fn:
let array: [usize; 5] = core::array::from_fn(|i| i * 2);
assert_eq!(array, [0, 2, 4, 8, 10]);
For your specific case, you can just use Default:
let v: [Vec<String>; 10] = Default::default();
For the general case, you can create an iterator out of your function and then collect into the array using ArrayVec:
use arrayvec::ArrayVec; // 0.4.10
use std::iter;
fn make<R>(f: impl FnMut() -> R) -> [R; 10] {
let a: ArrayVec<_> = iter::repeat_with(f).collect();
a.into_inner()
.unwrap_or_else(|_| panic!("Did not have enough elements"))
}
fn main() {
let mut a = 0;
let arr = make(|| {
a += 3;
a
});
println!("{:?}", arr);
// [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
}
See also:
How do I collect into an array?
I see two possible approaches
First
A simple solution using macro
macro_rules! array {
($v: expr; 1) => ([$v]);
($v: expr; 2) => ([$v, $v]);
($v: expr; 3) => ([$v, $v, $v]);
($v: expr; 4) => ([$v, $v, $v, $v]);
($v: expr; 5) => ([$v, $v, $v, $v, $v]);
// until 32
}
let a = array![Vec::new(); 3];
It's a bit verbose, but even the standard library uses this kind of construct.
Second
After realizing a connection between this question and another that I had answered before, I wrote this solution using nodrop
extern crate nodrop;
macro_rules! array {
($e: expr; $n:expr) => (
{
use std::mem;
use std::ptr;
use nodrop::NoDrop;
struct ArrayBuilder<T> {
len: usize,
data: *mut T,
}
impl<T> Drop for ArrayBuilder<T> {
fn drop(&mut self) {
unsafe {
while self.len > 0 {
let offset = (self.len as isize) - 1;
self.len -= 1;
ptr::drop_in_place(self.data.offset(offset));
}
}
}
}
let mut v: NoDrop<[_; $n]> = NoDrop::new(unsafe {
mem::uninitialized()
});
// helps type inference for v
if false { v[0] = $e; }
let mut builder = ArrayBuilder {
len: 0,
data: (&mut *v as *mut _) as *mut _
};
unsafe {
for i in 0..$n {
ptr::write(builder.data.offset(i as isize), $e);
builder.len = i + 1;
}
}
builder.len = 0;
v.into_inner()
}
)
}
let a = array![Vec::new(); 3];
And a test that indicates that it does not leak memory
#[test]
fn test() {
static mut COUNT: usize = 0;
#[derive(Debug)]
struct X(usize);
impl Drop for X {
fn drop(&mut self) {
println!("drop {:?}", self.0);
}
}
impl X {
fn new() -> X {
unsafe {
if COUNT == 3 {
panic!();
}
let x = X(COUNT);
COUNT += 1;
x
}
}
}
array![X::new(); 6];
}
In this test, the method X::new panics when creating X(3), so X(0), X(1), X(2) must be dropped.
Others
There is an unsafe solution here.
Edit: Outdated (applies to a Rust version lower than 1.55.0):
There is a crate called arr_macro that does exactly what you want:
fn main() {
let array: [Vec<String>; 10] = arr![Vec::new(); 10];
println!("{:?}", array) // [[], [], [], [], [], [], [], [], [], []]
}

Resources