How to reset all array elements? - arrays

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]);
}

Related

Syntax for updating underlying instance when looping?

I have a HashMap with different hashing algorithms which implement digest::DynDigest, but when they are looped over and update()d the final hash is always the same (Sha224 d14a...) (you can change the file PathBuf parameter to anything and get the exact same hash every time). So the update() and/or finalize() is not updating the instance in the HashMap.
What is the correct way to loop over the different hashers so that HashMap keeps correct updated state?
use digest::{Digest, DynDigest}; // https://crates.io/crates/digest/reverse_dependencies
use sha2; // implements digest::DynDigest
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::{BufReader, Read};
use std::path::PathBuf;
fn checksum_to_hex(bytes: &[u8]) -> String {
let mut s: String = String::new();
for b in bytes {
s.push_str(format!("{:02x}", b).as_str());
}
s
}
pub fn hash_file(
fpath: PathBuf,
hashers: HashMap<&str, Box<dyn DynDigest>>,
) -> io::Result<HashMap<&str, String>> {
let f = File::open(fpath).expect("failed to open file for hashing");
let mut buffer = [0u8; 1048576];
let mut reader = BufReader::new(f);
loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
break;
}
for (_, mut hasher) in hashers.to_owned() {
hasher.update(&buffer[..count]);
}
}
// Hash results per hasher
let mut hashes: HashMap<&str, String> = HashMap::new();
for (k, hasher) in hashers.to_owned() {
let res = checksum_to_hex(hasher.finalize().to_vec().as_slice());
hashes.insert(k, res);
}
Ok(hashes)
}
fn main() {
let mut hashers: HashMap<&str, Box<dyn DynDigest>> = HashMap::new();
hashers.insert("Sha224", Box::new(sha2::Sha224::new()));
hashers.insert("Sha256", Box::new(sha2::Sha256::new()));
hashers.insert("Sha512", Box::new(sha2::Sha512::new()));
for (htype, hashres) in hash_file(PathBuf::from("/bin/ls"), hashers).expect("") {
println!(" {} {}", htype, hashres);
}
}
Rust Playground
You need to replace the first hashers.to_owned() with hashers.iter_mut():
pub fn hash_file(
fpath: PathBuf,
mut hashers: HashMap<&str, Box<dyn DynDigest>>,
) -> io::Result<HashMap<&str, String>> {
let f = File::open(fpath).expect("failed to open file for hashing");
let mut buffer = [0u8; 1048576];
let mut reader = BufReader::new(f);
loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
break;
}
for (_, hasher) in hashers.iter_mut() {
// or `for hasher in hashers.values_mut()`
hasher.update(&buffer[..count]);
}
}
// Hash results per hasher
let mut hashes: HashMap<&str, String> = HashMap::new();
for (k, hasher) in hashers {
let res = checksum_to_hex(hasher.finalize().to_vec().as_slice());
hashes.insert(k, res);
}
Ok(hashes)
}
playground
.to_owned() will clone (create an independent deep copy) the map. When you iterate over that, you're iterating through a different map than the one you eventually return.
Instead, you want to iterate over references to the elements: this is what .iter_mut() (or .values_mut() if you only need the values) will give you.
This way, you don't need the second .to_owned(), but you do need to mark the hashers argument as mutable.

Is it possible to "combine" similar types in rust match assignment? [duplicate]

This question already has an answer here:
Multiple return types in rust [duplicate]
(1 answer)
Closed 10 months ago.
I'm trying to implement a function in rust that iterates either on the StdIn Lines or a BuffReader Lines.
Both types have lines.next() method. After that, the code is just String manipulation that works.
I originally made it worked (with repetitive and implicitly-typed branches) but the two branches had similar code. This gave me the impression I can DRY/refactor my code better.
The problem is (I think) that my two match branches, in main, do not return exactly the same type. Is it possible to make them "stick together" because I'm only using one common method? (It reminds me of Python duck typing)
Here's my refacto try:
use clap::Parser;
use exitcode;
use std::any::Any;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Lines, Write};
fn colorist(lines: &mut dyn Any, mut writer: impl std::io::Write) {
while let Some(line_wrap) = lines.next() {
match line_wrap {
Ok(line) => {
// ...
let buffer = "Some value base on line";
match writeln!(writer, "{}", buffer){
Ok(()) => (),
Err(e) => {eprintln!("{:?}", e);}
};
},
Err(e) => {eprintln!("{:?}", e);}
}
}
}
fn main() {
let args = Args::parse(); // have one '--file' arg being a filepath or is a empty str ("")
let mut writer = io::stdout();
let mut lines: Lines<dyn Any> = match args.file.is_empty() { // either read from stdin or read the file
false => {
let file = File::open(args.file).unwrap();
let reader = BufReader::new(file);
reader.lines() // type `std::io::Lines<BufReader<File>>`
},
true => {
let stdin = io::stdin();
stdin.lock().lines() // type `std::io::Lines<StdinLock<'_>>`
}
};
colorist(&mut lines, &mut writer);
}
This is a toy project, and I'm still learning rust on my free time. I might have some bad designs there and here.
As #PitaJ & #Chayim-friedman suggested, Either solved my problem.
I ended up with:
use either::*;
fn colorist(lines: &mut Either<Lines<BufReader<File>>, Lines<StdinLock>>, mut writer: impl std::io::Write) {...}
fn main() {
let args = Args::parse();
let mut writer = io::stdout();
let stdin = io::stdin();
let mut lines = match args.file.is_empty(){
false => {
let file = File::open(args.file).unwrap();
let reader = BufReader::new(file);
either::Left(reader.lines())
},
true => {
either::Right(stdin.lock().lines())
}
};
colorist(&mut lines, &mut writer);
match write!(writer, "{}", RESET){
_ => (),
};
let _ = writer.flush();
std::process::exit(exitcode::OK);
}

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

Multiple borrow in previous iteration of loop

Following is the code I'm working on, I explore a directory path with a queue and I want to store the filesystem tree in my data structure (the enum Entry):
use failure::Error;
use std::collections::VecDeque;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
fn main() -> Result<(), Error> {
let paths = visit_dir(Path::new(".")).map_err(Error::from)?;
Ok(())
}
#[derive(Debug)]
enum Entry {
Dir(PathBuf, Vec<Entry>),
File(PathBuf),
}
impl Entry {
fn new_dir(path: &Path) -> Entry {
Entry::Dir(path.to_path_buf(), Vec::new())
}
fn new_file(path: &Path) -> Entry {
Entry::File(path.to_path_buf())
}
/// Append a new Entry to self if self is a directory.
fn push(&mut self, path: &Path) -> Option<&mut Entry> {
if let Entry::Dir(_, ref mut content) = self {
let entry = if path.is_dir() {
Entry::new_dir(path)
} else {
Entry::new_file(path)
};
content.push(entry);
return content.last_mut();
}
None
}
fn path(&self) -> &Path {
match self {
Entry::Dir(path, _) => path,
Entry::File(path) => path,
}
}
}
fn visit_dir(root: &Path) -> io::Result<Entry> {
let mut dir = Entry::new_dir(root);
let mut queue = VecDeque::new();
queue.push_back(&mut dir);
while !queue.is_empty() {
let parent = queue.pop_front().unwrap();
let path = parent.path();
if path.is_dir() {
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
let entry = parent.push(&path).unwrap();
if path.is_dir() {
queue.push_back(entry);
}
}
}
}
Ok(dir)
}
Link to Playground
The error I am getting is:
error[E0499]: cannot borrow `*parent` as mutable more than once at a time
--> src/main.rs:61:29
|
61 | let entry = parent.push(&path).unwrap();
| ^^^^^^ mutable borrow starts here in previous iteration of loop
My questions are:
Why exactly do I get this error?
Are there any workaround to solve it?
entry borrows parent mutably in the line:
let entry = parent.push(&path).unwrap();
Then, you do not release entry, because you store it in queue. So, parent is still borrowed mutably when this is the 2nd iteration in the loop. This is unsafe to do that.
What you are trying to do is a tree of mutable references. That won't work in Rust, and this is generally a bad idea. You should modify the way you want to implement that.

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.

Resources