Error trying to slice bytes expected `usize`, found `u32` - rust

Im trying to slice into a buffer but am getting an error.
let mut buf = Vec::new();
let mut dst = [0u8; 4];
let read_index = 0;
dst.clone_from_slice(&buf[read_index..(read_index+3)]);
let length = u32::from_be_bytes(dst);
&buf[(read_index+4)..(read_index+length)]
error[E0308]: mismatched types
--> src/main.rs:28:79
|
28 | let trade = root_as_fb_iq_feed_trade(&buf[(read_index+4)..(read_index+length)]);
| ^^^^^^ expected `usize`, found `u32`
error[E0277]: cannot add `u32` to `usize`
--> src/main.rs:28:78
|
28 | let trade = root_as_fb_iq_feed_trade(&buf[(read_index+4)..(read_index+length)]);
| ^ no implementation for `usize + u32`
|
= help: the trait `Add<u32>` is not implemented for `usize`

let mut buf = Vec::new();
let read_index = 0;
dst.clone_from_slice(&buf[read_index..(read_index+3)]);
let length = usize::from_be_bytes(dst); // u32 -> usize
&buf[(read_index+4)..(read_index+length)]
usize supports the from_be_bytes method: The Rust doc of size::from_be_bytes
The error info from the compiler is clear enough to make you write the code that works. There is also specification on the doc I mentioned above, the function from_be_bytes only accepts the param as [u8; 8], so there is one more modification:
let mut buf = Vec::new();
let mut dst = [0u8; 8]; // Expand your buffer to the size of 8
let read_index = 0;
dst.clone_from_slice(&buf[read_index..(read_index+3)]);
let length = usize::from_be_bytes(dst);
&buf[(read_index+4)..(read_index+length)]

let length = u32::from_be_bytes(dst);
let length_us = usize::try_from(length).unwrap();

Related

Peek iterator inside `for` loop

I'm trying to peek at the char in-front of my current location whilst iterating over a &str.
let myStr = "12345";
let mut iter = myStr.chars().peekable();
for c in iter {
let current: char = c;
let next: char = *iter.peek().unwrap_or(&'∅');
}
I will be passing this char into a method down the line. However, even this MRE produces a borrow after move error that I'm not sure how to get past.
error[E0382]: borrow of moved value: `iter`
--> src/lib.rs:7:27
|
4 | let mut iter = myStr.chars().peekable();
| -------- move occurs because `iter` has type `Peekable<Chars<'_>>`, which does not implement the `Copy` trait
5 | for c in iter {
| ---- `iter` moved due to this implicit call to `.into_iter()`
6 | let current: char = c;
7 | let next: char = *iter.peek().unwrap_or(&'∅');
| ^^^^^^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `iter`
--> /home/james/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:267:18
|
267 | fn into_iter(self) -> Self::IntoIter;
Any idea what's going on here? I've tried various combinations of referencing and dereferencing but nothing I've tried seems to work.
The iterator is moved into the for loop. You cannot manually manipulate an iterator inside a for loop. However, the for loop can be replaced by while let:
while let Some(c) = iter.next() {
let current: char = c;
let next: char = *iter.peek().unwrap_or(&'∅');
}
Playground.
If you can work with slices, it will get much easier with windows():
let slice = ['1', '2', '3', '4', '5'];
let iter = slice.windows(2);
for arr in iter {
let current = arr[0];
let next = arr[1];
}
Playground

Error reading from BufReader in nested loops

I am been working on a program in Rust to read individual lines from a local text file, divide the line into a character vector and do some other operations. This is the snippet of my code:
use std::io::{BufRead, BufReader};
use std::fs::File;
fn main() {
// ----<code snippet>-----
let input_file = File::open("--<text file location>--").unwrap();
let input_file = BufReader::new(input_file);
let mut temp2 = String::new();
let mut counter = 0;
while counter < 12 {
for line in input_file.lines() {
let input_line = line.expect("Failed to read line");
let temp: Vec<char> = input_line.chars().collect::<Vec<_>>();
temp2.push(temp[counter]);
}
//-----<program continues without any issues>-------
Here is the error message as shown up in Cargo:
error[E0382]: use of moved value: `input_file`
--> src\main.rs:48:21
|
42 | let input_file = BufReader::new(input_file);
| ---------- move occurs because `input_file` has type `BufReader<File>`, which does not implement the `Copy` trait
...
48 | for line in input_file.lines() {
| ^^^^^^^^^^ ------- `input_file` moved due to this method call, in previous iteration of loop
|
note: this function takes ownership of the receiver `self`, which moves `input_file`
--> C:\Users\Gumbi\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\std\src\io\mod.rs:2258:14
|
2258 | fn lines(self) -> Lines<Self>
| ^^^^
error[E0382]: borrow of moved value: `temp2`
--> src\main.rs:51:13
|
44 | let mut temp2 = String::new();
| --------- move occurs because `temp2` has type `String`, which does not implement the `Copy` trait
...
51 | temp2.push(temp[counter]);
| ^^^^^ value borrowed here after move
...
54 | let temp3 = most_common_digit(temp2);
| ----- value moved here, in previous iteration of loop
I know the basics of ownership and borrowing, but I am not able to grasp what is the problem in this code. Could anyone please help me in knowing where I am going wrong?
The problem is that input_file is moved inside the while loop scope. Instead use an intermediary &mut that can be dropped in each iteration:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
// ----<code snippet>-----
let input_file = File::open("--<text file location>--").unwrap();
let mut input_file = BufReader::new(input_file);
let mut temp2 = String::new();
let mut counter = 0;
while counter < 12 {
let mut input_file_ref = &mut input_file;
for line in input_file_ref.lines() {
let input_line = line.expect("Failed to read line");
let temp: Vec<char> = input_line.chars().collect::<Vec<_>>();
temp2.push(temp[counter]);
}
}
}
Playground

Type mismatch error trying to intialize vector with type

I'm trying to create a msg_bytes buffer to store data. But when creating it I get a type mismatch error.
use libflate::gzip::Decoder;
let mut f = std::fs::File::open("./20181002.bytes").unwrap();
let mut decoder = Decoder::new(&f).unwrap();
let mut msglen_bytes = [0u8; 4];
decoder.read_exact(&mut msglen_bytes).unwrap();
println!("msglen_bytes: {:?}", &msglen_bytes);
let length = u32::from_le_bytes(msglen_bytes);
let length_us = usize::try_from(length).unwrap();
println!("length: {}", length);
let mut msg_bytes = vec!(0u8, length_us, length_us);
let mut msg_bytes = [0u8; length_us]; // Option 2
decoder.read_exact(&mut msg_bytes).unwrap();
error[E0308]: mismatched types
--> src/main.rs:50:35
|
50 | let mut msg_bytes = vec!(0u8, length_us, length_us);
| ^^^^^^^^^ expected `u8`, found `usize`
If I run with Option 2 I get:
error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:51:31
|
47 | let length_us = usize::try_from(length).unwrap();
| ------------- help: consider using `const` instead of `let`: `const length_us`
...
51 | let mut msg_bytes = [0u8; length_us];
| ^^^^^^^^^ non-constant value
You probably want let msg_bytes = vec![0u8; length_us] (note semicolon between 0u8 and the length).
vec!(0u8, length_us, length_us) attempts to create a 3-element vector whose elements have values 0u8, length_us, and length_us respectively. Since all vector elements must be of the same type, that syntax can't compile.
Option 2 doesn't compile because arrays must have sizes determined at compile time.

How do I convert two u8 primitives into a u16 primitive?

I'm reading a binary file into a Rust program using a Vec<u8> as a buffer. Two bytes in the stream represent a big-endian u16.
So far, the only way I've figured out how to convert to a primitive u16 involves converting the two elements to Strings first, and it looks terrible.
Code:
let vector: Vec<u8> = [1, 16].to_vec();
let vector0: String = format!("{:02x}", vector[0]);
let vector1: String = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0.clone();
vector_combined = vector_combined + &vector1.clone();
let number: u16 = u16::from_str_radix(&vector_combined.to_string(), 16).unwrap();
println!("vector[0]: 0x{:02x}", vector[0]);
println!("vector[1]: 0x{:02x}", vector[1]);
println!("number: 0x{:04x}", number);
Output:
vector[0]: 0x01
vector[1]: 0x10
number: 0x0110
If you actually had two distinct u8s, the conventional solution involves bitwise manipulation, specifically shifting and bitwise OR. This requires zero heap allocation and is very efficient:
let number = ((vector[0] as u16) << 8) | vector[1] as u16;
And a graphical explanation:
A0 B0
+--------+ +--------+
|XXXXXXXX| |YYYYYYYY|
+-------++ +-------++
| |
A1 = A0 as u16 | B1 = B0 as u16 |
+---------------v+ +---------------v+
|00000000XXXXXXXX| |00000000YYYYYYYY|
+---------------++ +---------------++
| |
A2 = A1 << 8 | |
+---------------v+ |
|XXXXXXXX00000000| |
+---------------++ |
| +--+ |
+-------------->OR<--+
+-++
|
V = A2 | B1 |
+----------+----v+
|XXXXXXXXYYYYYYYY|
+----------------+
However, you are really looking at your problem too narrowly. You don't have two u8, you have a &[u8].
In this case, use the byteorder crate:
use byteorder::{ByteOrder, LittleEndian}; // 1.3.4
fn main() {
let data = [1, 16];
let v = LittleEndian::read_u16(&data);
println!("{}", v);
}
This shows its power when you want to handle reading through the buffer:
use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; // 1.3.4
fn main() {
let data = [1, 16, 1, 2];
let mut current = &data[..];
let v1 = current.read_u16::<LittleEndian>();
let v2 = current.read_u16::<BigEndian>();
println!("{:?}, {:?}", v1, v2); // Ok(4097), Ok(258)
}
As you can see, you need to be conscious of the endianness of your input data.
You could also get a fixed-size array from your slice and then use u16::from_le_bytes. If you had a &[u8] and wanted to get a Vec<u16>, you can iterate over appropriately-sized slices using chunks_exact (or array_chunks).
See also:
How do you set, clear and toggle a single bit in Rust?
Temporarily transmute [u8] to [u16]
How do I convert a Vec<T> to a Vec<U> without copying the vector?
Free code review on your original post:
There's no need to use to_vec here, use vec! instead.
There's no need to specify the vast majority of the types.
let vector = [1u8, 16].to_vec();
let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0.clone();
vector_combined = vector_combined + &vector1.clone();
let number = u16::from_str_radix(&vector_combined.to_string(), 16).unwrap();
There's no need to clone the strings before taking a reference to them when adding.
There's no need to convert the String to... another String in from_str_radix.
let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0;
vector_combined = vector_combined + &vector1;
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
There's no need to create an empty String to append to, just use vector0
let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let vector_combined = vector0 + &vector1;
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
There's no need to create two strings at all, one will do:
let vector_combined = format!("{:02x}{:02x}", vector[0], vector[1]);
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
Of course, this still isn't the right solution, but it's better.
You can multiply the first element to move it to the higher byte, then add the second element. It just needs extra casting:
let a: u8 = 1;
let b: u8 = 2;
let c: u16 = (a as u16 * 256) + b as u16;
println!("c: {}", c); // c: 258

How do I concatenate two slices in Rust?

I want to take the x first and last elements from a vector and concatenate them. I have the following code:
fn main() {
let v = (0u64 .. 10).collect::<Vec<_>>();
let l = v.len();
vec![v.iter().take(3), v.iter().skip(l-3)];
}
This gives me the error
error[E0308]: mismatched types
--> <anon>:4:28
|
4 | vec![v.iter().take(3), v.iter().skip(l-3)];
| ^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Take`, found struct `std::iter::Skip`
<anon>:4:5: 4:48 note: in this expansion of vec! (defined in <std macros>)
|
= note: expected type `std::iter::Take<std::slice::Iter<'_, u64>>`
= note: found type `std::iter::Skip<std::slice::Iter<'_, u64>>`
How do I get my vec of 1, 2, 3, 8, 9, 10? I am using Rust 1.12.
Just use .concat() on a slice of slices:
fn main() {
let v = (0u64 .. 10).collect::<Vec<_>>();
let l = v.len();
let first_and_last = [&v[..3], &v[l - 3..]].concat();
println!("{:?}", first_and_last);
// The output is `[0, 1, 2, 7, 8, 9]`
}
This creates a new vector, and it works with arbitrary number of slices.
(Playground link)
Ok, first of all, your initial sequence definition is wrong. You say you want 1, 2, 3, 8, 9, 10 as output, so it should look like:
let v = (1u64 .. 11).collect::<Vec<_>>();
Next, you say you want to concatenate slices, so let's actually use slices:
let head = &v[..3];
let tail = &v[l-3..];
At this point, it's really down to which approach you like the most. You can turn those slices into iterators, chain, then collect...
let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
...or make a vec and extend it with the slices directly...
let mut v3 = vec![];
v3.extend_from_slice(head);
v3.extend_from_slice(tail);
...or extend using more general iterators (which will become equivalent in the future with specialisation, but I don't believe it's as efficient just yet)...
let mut v4: Vec<u64> = vec![];
v4.extend(head);
v4.extend(tail);
...or you could use Vec::with_capacity and push in a loop, or do the chained iterator thing, but using extend... but I have to stop at some point.
Full example code:
fn main() {
let v = (1u64 .. 11).collect::<Vec<_>>();
let l = v.len();
let head = &v[..3];
let tail = &v[l-3..];
println!("head: {:?}", head);
println!("tail: {:?}", tail);
let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
println!("v2: {:?}", v2);
let mut v3 = vec![];
v3.extend_from_slice(head);
v3.extend_from_slice(tail);
println!("v3: {:?}", v3);
// Explicit type to help inference.
let mut v4: Vec<u64> = vec![];
v4.extend(head);
v4.extend(tail);
println!("v4: {:?}", v4);
}
You should collect() the results of the take() and extend() them with the collect()ed results of skip():
let mut p1 = v.iter().take(3).collect::<Vec<_>>();
let p2 = v.iter().skip(l-3);
p1.extend(p2);
println!("{:?}", p1);
Edit: as Neikos said, you don't even need to collect the result of skip(), since extend() accepts arguments implementing IntoIterator (which Skip does, as it is an Iterator).
Edit 2: your numbers are a bit off, though; in order to get 1, 2, 3, 8, 9, 10 you should declare v as follows:
let v = (1u64 .. 11).collect::<Vec<_>>();
Since the Range is left-closed and right-open.

Resources