How to move a range of elements from BytesMut? - rust

I have a method that takes a mutable instance of BytesMut. I want to move chunks of it into other instances of BytesMut but am not sure about the syntax to do so. Are there any examples out there?

You could use the range operator on the original buf to move things around or split_off based on some offset value. For example:
use bytes::{BufMut, BytesMut};
fn main() {
let mut buf = BytesMut::with_capacity(64);
let mut buf_to = BytesMut::with_capacity(64);
buf.put_u8(b't');
buf.put_u8(b'e');
buf.put_u8(b's');
buf.put_u8(b't');
// move last 2 elements
buf_to.put(&buf[2..]);
println!("{:#?}", buf_to); // b"st"
// You can also split_off the original value
let mut another_buf = buf.split_off(2);
println!("{:#?}", another_buf); // b"st"
println!("{:#?}", buf); // b"te"
}

Related

What is the most efficient way to read the first line of a file separately to the rest of the file?

I am trying to figure out the best way to read the contents of a file. The problem is that I need to read the first line separately, because I need that to be parsed as a usize which I need for the dimension of a Array2 by ndarray.
I tried the following:
use ndarray::prelude::*;
use std::io:{BufRead,BufReader};
use std::fs;
fn read_inputfile(geom_filename: &str) -> (Vec<i32>, Array2<f64>, usize) {
//* Step 1: Read the coord data from input
println!("Inputfile: {geom_filename}");
let geom_file = fs::File::open(geom_filename).expect("Geometry file not found!");
let geom_file_reader = BufReader::new(geom_file);
let geom_file_lines: Vec<String> = geom_file_reader
.lines()
.map(|line| line.expect("Failed to read line!"))
.collect();
//* Read no of atoms first for array size
let no_atoms: usize = geom_file_lines[0].parse().unwrap();
let mut Z_vals: Vec<i32> = Vec::new();
let mut geom_matr: Array2<f64> = Array2::zeros((no_atoms, 3));
for (atom_idx, line) in geom_file_lines[1..].iter().enumerate() {
//* into_iter would do the same
let line_split: Vec<&str> = line.split_whitespace().collect();
Z_vals.push(line_split[0].parse().unwrap());
(0..3).for_each(|cart_coord| {
geom_matr[(atom_idx, cart_coord)] = line_split[cart_coord + 1].parse().unwrap();
});
}
(Z_vals, geom_matr, no_atoms)
}
Does this not kind of defeat the purpose of the BufReader? I am still relative new to Rust, so I might have misunderstood something, but I thought that one uses the BufReader so that the whole file does not need to be read into memory.
With the Vec<String> for geom_file_lines I am mostlike loading the whole file into memory again, right?
Does this not kind of defeat the purpose of the BufReader?
It very much does, yes. lines() gives you an iterator, so you can read them without loading all of them into memory at once. You force them all into memory, though, as you call collect().
Simply don't do that. Use the iterator as an iterator. Especially as you convert it back to an iterator later, via geom_file_lines[1..].iter().
Like this:
use ndarray::prelude::*;
use std::fs;
use std::io::{BufRead, BufReader};
pub fn read_inputfile(geom_filename: &str) -> (Vec<i32>, Array2<f64>, usize) {
//* Step 1: Read the coord data from input
println!("Inputfile: {geom_filename}");
let geom_file = fs::File::open(geom_filename).expect("Geometry file not found!");
let geom_file_reader = BufReader::new(geom_file);
let mut geom_file_lines = geom_file_reader
.lines()
.map(|line| line.expect("Failed to read line!"));
//* Read no of atoms first for array size
let no_atoms: usize = geom_file_lines.next().unwrap().parse().unwrap();
let mut z_vals: Vec<i32> = Vec::new();
let mut geom_matr: Array2<f64> = Array2::zeros((no_atoms, 3));
for (atom_idx, line) in geom_file_lines.enumerate() {
let line_split: Vec<&str> = line.split_whitespace().collect();
z_vals.push(line_split[0].parse().unwrap());
(0..3).for_each(|cart_coord| {
geom_matr[(atom_idx, cart_coord)] = line_split[cart_coord + 1].parse().unwrap();
});
}
(z_vals, geom_matr, no_atoms)
}
You can apply the same logic in your for loop:
for (atom_idx, line) in geom_file_lines.enumerate() {
let mut line_split = line.split_whitespace();
z_vals.push(line_split.next().unwrap().parse().unwrap());
(0..3).for_each(|cart_coord| {
geom_matr[(atom_idx, cart_coord)] = line_split.next().unwrap().parse().unwrap();
});
}

Populating a Hashmap with a vector of string slices in rust

I've been pulling my hair out with this one.
I apologize in advance if it's a poorly worded question.
So, I have a Hashmap in the outer scope and want to populate it with string slices.
// Hashmap declaration.
let mut words: std::collections::HashMap< &str, std::vec::Vec<&str> > = std::collections::HashMap::new();
for file_name in ["conjuctions", "nouns", "verbs"].iter() { // Reading some file.
let file_content = std::fs::read_to_string("../wordlists/{file_name}.txt");
let mut fc = match file_content {
Ok(file_content) => file_content,
Err(_) => panic!("Failed to read the file: ../wordlists/{file_name}.txt"),
};
let mut wordlist_vec: Vec<&str> = fc.split("\n").collect();
words.insert( file_name, wordlist_vec );
}
println!(words["conjunctions"])
// Using it outside the above scope throws an error. That FC was dropped but still borrowed.
So basically, my question is, how can I use the hash map outside the scope for the loop above?
I think the issues emanate from using string slices (split returns slices ig) but I'm not too sure.
You simply need to use an owned String instead of &strs.
let mut words: HashMap<String, Vec<String>> = HashMap::new();
// ...
// We use map to change the elements of the iterator to owned Strings.
let mut wordlist_vec: Vec<String> = fc.split("\n").map(String::from).collect();
words.insert(file_name.to_string(), wordlist_vec);

Rust peekable double reference

Why does a peekable iterator return a double reference in an Option?
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
let next = iter.peek();
next is an Option<&&Foo>, not an Option<&Foo>.
How do I get it to be the latter?
I do not want to use .into_iter() because I do not want to consume the vec. I just want a borrowed reference to the Foo struct wrapped in an Option.
peek yields references to whatever you're iterating over. If that's also references, it'll yield double references. You can use the copied Option adapter to remove that level of indirection:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
// use `copied` here to go from Option<&&_> to Option<&_>
let next = iter.peek().copied();
Alternatively, you can just call next after you checked that you want the peeked value:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
if is_okay(iter.peek()) {
let next = iter.next(); // `next` has type `&Foo`
}
You could even use pattern matching to remove one level of indirection:
if let Some(&next) = iter.peek() {
// `next` has type `&Foo` in this block
}

Why do String::from(&str) and &str.to_string() behave differently in Rust?

fn main() {
let string = "Rust Programming".to_string();
let mut slice = &string[5..12].to_string(); // Doesn't work...why?
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}
What is happening here? Please explain.
The main issue here that & have lower priority than method call.
So, actual code is
let mut slice = &(string[5..12].to_string());
So you a taking a reference to temporary String object that dropped and cannot be used later.
You should wrap your reference in parenthesis and call the method on the result.
fn main() {
let string = "Rust Programming".to_string();
let mut slice = (&string[5..12]).to_string(); // ! -- this should work -- !
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}

Default mutable value from HashMap

Suppose I have a HashMap and I want to get a mutable reference to an entry, or if that entry does not exist I want a mutable reference to a new object, how can I do it? I've tried using unwrap_or(), something like this:
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut ref = map.get_mut("whatever").unwrap_or( &mut Vec::<&str>::new() );
// Modify ref.
}
But that doesn't work because the lifetime of the Vec isn't long enough. Is there any way to tell Rust that I want the returned Vec to have the same lifetime as foo()? I mean there is this obvious solution but I feel like there should be a better way:
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut dummy: Vec<&str> = Vec::new();
let mut ref = map.get_mut("whatever").unwrap_or( &dummy );
// Modify ref.
}
As mentioned by Shepmaster, here is an example of using the entry pattern. It seems verbose at first, but this avoids allocating an array you might not use unless you need it. I'm sure you could make a generic function around this to cut down on the chatter :)
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
fn foo() {
let mut map = HashMap::<&str, Vec<&str>>::new();
let mut result = match map.entry("whatever") {
Vacant(entry) => entry.insert(Vec::new()),
Occupied(entry) => entry.into_mut(),
};
// Do the work
result.push("One thing");
result.push("Then another");
}
This can also be shortened to or_insert as I just discovered!
use std::collections::HashMap;
fn foo() {
let mut map = HashMap::<&str, Vec<&str>>::new();
let mut result = map.entry("whatever").or_insert(Vec::new());
// Do the work
result.push("One thing");
result.push("Then another");
}
If you want to add your dummy into the map, then this is a duplicate of How to properly use HashMap::entry? or Want to add to HashMap using pattern match, get borrow mutable more than once at a time (or any question about the entry API).
If you don't want to add it, then your code is fine, you just need to follow the compiler error messages to fix it. You are trying to use a keyword as an identifier (ref), and you need to get a mutable reference to dummy (& mut dummy):
use std::collections::HashMap;
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut dummy: Vec<&str> = Vec::new();
let f = map.get_mut("whatever").unwrap_or( &mut dummy );
}
fn main() {}

Resources