Lifetime and borrowing const arrays [duplicate] - arrays

This question already has an answer here:
Getting 'Missing Lifetime specifier' error
(1 answer)
Closed last year.
I'm starting to study Rust and I admit, I have some problems with lifetimes and borrowing. On even days I think I got it and on odd days I get bitten ! Too much C or C++ ? Or perhaps too old ?
;-)
The following code does not compile:
use core::f64::consts::PI;
pub struct TableOscillator {
sample_rate: u32,
table: &[f64],
}
impl TableOscillator {
pub fn new(sample_rate: u32, table: &[f64]) -> TableOscillator {
TableOscillator { sample_rate, table }
}
// Other methods ...
}
fn main() {
const SAMPLE_RATE: u32 = 96000;
let table: [f64; 1024];
for i in 0..table.len() {
let phase = (2.0 * PI * i as f64) / (table.len() as f64);
table[i] = phase.sin();
}
// At this point I would like "table" to be constant and usable by all the following oscillators.
let osc1 = TableOscillator::new(SAMPLE_RATE, &table);
let osc2 = TableOscillator::new(SAMPLE_RATE, &table);
// ...
}
Here is the compiler message:
error[E0106]: missing lifetime specifier
--> src/main.rs:5:12
|
5 | table: &[f64],
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
3 ~ pub struct TableOscillator<'a> {
4 | sample_rate: u32,
5 ~ table: &'a [f64],
|
A bit of explanation: the different oscillators use their "table" members (only read no write).
What is the Rust idiomatic way to fix that ?
Thanks !

In order to do this you need to annotate the lifetime for TableOscillator to tell Rust that the reference needs to live as long as the struct:
pub struct TableOscillator<'a> {
sample_rate: u32,
table: &'a [f64],
}
osc1 and osc2 cannot outlive table, because they're borrowing it.
See Validating References with Lifetimes.

Related

How can I return a Chain iterator with data added from a temporary array?

I'm writing a MQTT5 library. To send a packet, I need to know the size of the payload before writing the payload. My solution for determining the size has the following constraints order by importance:
be easy to maintain
should not create copies of the data
should be fairly performant (avoid double calculations)
To determine the size I can do any of the following solutions:
do the calculations by hand, which is fairly annoying
hold a copy of the data to send in memory, which I want to avoid
Build an std::iter::ExactSizeIterator for the payload which consists of std::iter::Chains itself, which leads to ugly typings fast, if you don't create wrapper types
I decided to go with version 3.
The example below shows my try on writing a MQTT String iterator. A MQTT String consists of two bytes which are the length of the string followed by the data as utf8.
use std::iter::*;
use std::slice::Iter;
pub struct MQTTString<'a> {
chain: Chain<Iter<'a, u8>, Iter<'a, u8>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let len_bytes = u16_len.to_be_bytes();
let len_iter = len_bytes.iter(); // len_bytes is borrowed here
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter();
let chain = len_iter.chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = &'a u8;
fn next(&mut self) -> Option<&'a u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
pub struct MQTTStringPait<'a> {
chain: Chain<std::slice::Iter<'a, u8>, std::slice::Iter<'a, u8>>,
}
This implementation doesn't compile because I borrow len_bytes instead of moving it, so it'd get dropped before the Chain can consume it:
error[E0515]: cannot return value referencing local variable `len_bytes`
--> src/lib.rs:19:9
|
12 | let len_iter = len_bytes.iter(); // len_bytes is borrowed here
| --------- `len_bytes` is borrowed here
...
19 | MQTTString { chain }
| ^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
Is there a nice way to do this? Adding len_bytes to the MQTTString struct doesn't help. Is there a better fourth option of solving the problem?
The root problem is that iter borrows the array. In nightly Rust, you can use array::IntoIter, but it does require that you change your iterator to return u8 instead of &u8:
#![feature(array_value_iter)]
use std::array::IntoIter;
use std::iter::*;
use std::slice::Iter;
pub struct MQTTString<'a> {
chain: Chain<IntoIter<u8, 2_usize>, Copied<Iter<'a, u8>>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let len_bytes = u16_len.to_be_bytes();
let len_iter = std::array::IntoIter::new(len_bytes);
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter().copied();
let chain = len_iter.chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
You could do the same thing in stable Rust by using a Vec, but that'd be a bit of overkill. Instead, since you know the exact size of the array, you could get the values and chain more:
use std::iter::{self, *};
use std::slice;
pub struct MQTTString<'a> {
chain: Chain<Chain<Once<u8>, Once<u8>>, Copied<slice::Iter<'a, u8>>>,
}
impl<'a> MQTTString<'a> {
pub fn new(s: &'a str) -> Self {
let u16_len = s.len() as u16;
let [a, b] = u16_len.to_be_bytes();
let s_bytes = s.as_bytes();
let s_iter = s_bytes.iter().copied();
let chain = iter::once(a).chain(iter::once(b)).chain(s_iter);
MQTTString { chain }
}
}
impl<'a> Iterator for MQTTString<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.chain.next()
}
}
impl<'a> ExactSizeIterator for MQTTString<'a> {}
See also:
How to implement Iterator and IntoIterator for a simple struct?
An iterator of &u8 is not a good idea from the point of view of pure efficiency. On a 64-bit system, &u8 takes up 64 bits, as opposed to the 8 bits that the u8 itself would take. Additionally, dealing with this data on a byte-by-byte basis will likely impede common optimizations around copying memory around.
Instead, I'd recommend creating something that can write itself to something implementing Write. One possible implementation:
use std::{
convert::TryFrom,
io::{self, Write},
};
pub struct MQTTString<'a>(&'a str);
impl MQTTString<'_> {
pub fn write_to(&self, mut w: impl Write) -> io::Result<()> {
let len = u16::try_from(self.0.len()).expect("length exceeded 16-bit");
let len = len.to_be_bytes();
w.write_all(&len)?;
w.write_all(self.0.as_bytes())?;
Ok(())
}
}
See also:
How do I convert between numeric types safely and idiomatically?
Converting number primitives (i32, f64, etc) to byte representations

Why can I not mutably borrow a variable in two different map functions?

I have an iterator in Rust that loops over a Vec<u8> and applies the same function at two different stages. I do this by chaining a couple of map functions together. Here is the relevant code (where example, example_function_1, and example_function_2 are stand-in variables and functions respectively):
NOTE: example.chunks() is a custom function! Not the default one on slices!
let example = vec![0, 1, 2, 3];
let mut hashers = Cycler::new([example_function_1, example_function_2].iter());
let ret: Vec<u8> = example
//...
.chunks(hashers.len())
.map(|buf| hashers.call(buf))
//...
.map(|chunk| hashers.call(chunk))
.collect();
Here is the code for Cycler:
pub struct Cycler<I> {
orig: I,
iter: I,
len: usize,
}
impl<I> Cycler<I>
where
I: Clone + Iterator,
I::Item: Fn(Vec<u8>) -> Vec<u8>,
{
pub fn new(iter: I) -> Self {
Self {
orig: iter.clone(),
len: iter.clone().count(),
iter,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn reset(&mut self) {
self.iter = self.orig.clone();
}
pub fn call(&mut self, buf: Bytes) -> Bytes {
// It is safe to unwrap because it should indefinietly continue without stopping
self.next().unwrap()(buf)
}
}
impl<I> Iterator for Cycler<I>
where
I: Clone + Iterator,
I::Item: Fn(Vec<u8>) -> Vec<u8>,
{
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
match self.iter.next() {
next => next,
None => {
self.reset();
self.iter.next()
}
}
}
// No size_hint, try_fold, or fold methods
}
What confuses me is that the second time I reference hashers it says this:
error[E0499]: cannot borrow `hashers` as mutable more than once at a time
--> libpressurize/src/password/password.rs:28:14
|
21 | .map(|buf| hashers.call(buf))
| ----- ------- first borrow occurs due to use of `hashers` in closure
| |
| first mutable borrow occurs here
...
28 | .map(|chunk| hashers.call(chunk))
| --- ^^^^^^^ ------- second borrow occurs due to use of `hashers` in closure
| | |
| | second mutable borrow occurs here
| first borrow later used by call
Shouldn't this work because the mutable reference is not used at the same time?
Please let me know if more info/code is needed to answer this.
.map(|buf| hashers.call(buf))
You're probably thinking that in the above line, hashers is mutably borrowed to call it. That's true (since Cycler::call takes &mut self) but it's not what the compiler error is about. In this line, hashers is mutably borrowed to construct the closure |buf| hashers.call(buf), and that borrow lasts as long as the closure does.
Thus, when you write
.map(|buf| hashers.call(buf))
//...
.map(|chunk| hashers.call(chunk))
you are constructing two closures which live at the same time (assuming this is std::iter::Iterator::map) and mutably borrowing hashers for each of them, which is not allowed.
This error is actually protecting you against a side-effect hazard: it's not obvious (in a purely local analysis) what order the side effects of the two call()s will be performed in, because the map()s could do anything they like with the closures. Given the code you wrote, I assume you're doing this on purpose, but the compiler doesn't know that you know what you're doing.
(We can't even predict what the interleaving will be just because they're iterators. Inside of your //... there could be, say a .filter() step which leads to hashers.call(buf) being called several times between each call to hashers.call(chunk), or something else that produces a different number of outputs than inputs.)
If you know that you want the interleaving of side-effects that is “whenever either map() decides to call it”, then you can gain that freedom with a RefCell or other interior mutability, as dianhenglau's answer demonstrates.
Shouldn't this work because the mutable reference is not used at the same time?
No. The rules of references stated that "At any given time, you can have either one mutable reference or any number of immutable references", no matter if it is or isn't used at the same time. See this answer for the reason behind the rules.
As for workaround, since you're sure that the mutations do not occur simultaneously, you can use std::cell::RefCell as explained in this chapter. Modify the code into:
use std::cell::RefCell;
let example = vec![0, 1, 2, 3];
// Remove the "mut", wrap Cycler in RefCell.
let hashers = RefCell::new(Cycler::new([example_function_1, example_function_2].iter()));
let ret: Vec<u8> = example
//...
.chunks(hashers.borrow().len())
// Borrow hashers as immutable inside the closure, then borrow the Cycler as mutable.
.map(|buf| hashers.borrow_mut().call(buf))
//...
.map(|chunk| hashers.borrow_mut().call(chunk))
.collect();

Rust: access mutable argument in "while let"

But for example in the following code, I want to insert a value into a mutable BTreeMap/Hashmap in each loop, my simple solution triggered an error, what is the elegant way to do that in Rust?
Do I need clone the BTreeMap at the beginning of each loop?
pub fn build_string(word: &str, trie: &mut BTreeMap<&str, &Node>, word_index: usize) {
for char in word.chars() {
let char_label = char.to_string();
let insert_node = Node::new(&char_label, word_index);
let insert_result = trie.insert(&char_label, &insert_node);
println!("char: {}, at index", char);
}
}
error is
error[E0597]: `insert_node` does not live long enough
--> src/lib.rs:69:54
|
65 | pub fn build_string(word: &str, trie: &mut BTreeMap<&str, &Node>, word_index: usize) {
| - let's call the lifetime of this reference `'1`
...
69 | let insert_result = trie.insert(&char_label, &insert_node);
| -------------------------^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `insert_node` is borrowed for `'1`
70 | println!("char: {}, at index", char);
71 | }
| - `insert_node` dropped here while still borrowed
The issue is not with your BTreeMap but rather with the lifetime of your Node. You are creating a node inside the method build_string and trying to insert a reference to it into the map. However, once the method build_string goes out of scope, the local insert_node gets dropped but the reference would still exist in the tree. This is not allowed.
Therefore, you could change the BTreeMap to have values of Node instead of &Node. Then you would simply insert the insert_node into the tree which would take ownership of the node thus avoiding any reference leaks

Prevent 'static lifetime requirement in Rc<Trait>

Where is the 'static lifetime requirement coming from when using a trait type in std::rc::Rc and how can I prevent it? E.g. when trying to compile this code
trait Handler{}
fn add(a: std::rc::Rc<Handler>) {
}
fn main() {
add(0);
}
rust reports
error[E0308]: mismatched types
--> test.rs:7:9
...
= note: expected type `std::rc::Rc<Handler + 'static>`
found type `{integer}`
NOTE: the error itself is expected; I am just interested in the Handler + 'static diagnostic output. The Real program creates instances of a trait type, stores them into a HashMap and runs a type specific function on it. It fails to compile with
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
at this place.
Second example
The following code is more real-world and demonstrates the issue perhaps better:
trait Handler {
}
struct SomeHandler<'a>(&'a u32);
impl <'a> SomeHandler<'a> {
fn new(a: &'a u32) -> std::rc::Rc<Handler> {
std::rc::Rc::new(SomeHandler(a))
}
}
impl <'a> Handler for SomeHandler<'a> {
}
fn main() {
let a: u32;
SomeHandler::new(&a);
}
It fails with
8 | std::rc::Rc::new(SomeHandler(a))
| ^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::rc::Rc<Handler + 'static>
found std::rc::Rc<Handler>
Why explicit lifetimes do not work
The simple demo might be fixed by adding an explicit lifetime (e.g. Rc<Handler + 'a>). Unfortunately, this is not an option (nor trying to make anything 'static) because real code is intended to look like
struct PollRegistry {
...
handlers: std::collections::HashMap<mio::Token, std::rc::Weak<PollHandler>>,
}
impl PollRegistry {
fn register<'a>(&mut self, handler: &std::rc::Rc<PollHandler>,
interest: mio::Ready, opts: mio::PollOpt)
-> std::io::Result<()> {
....
self.handlers.insert(token, std::rc::Rc::downgrade(handler));
}
}
and methods in PollHandler specializations create and own other PollHandler specializations which are registered in the registry by these methods.
rustc 1.27.1

How to default-initialize a struct containing an array in Rust?

What is the recommended way to declare a struct that contains an array, and then create a zero-initialized instance?
Here is the struct:
#[derive(Default)]
struct Histogram {
sum: u32,
bins: [u32; 256],
}
and the compiler error:
error[E0277]: the trait bound `[u32; 256]: std::default::Default` is not satisfied
--> src/lib.rs:4:5
|
4 | bins: [u32; 256],
| ^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `[u32; 256]`
|
= help: the following implementations were found:
<[T; 14] as std::default::Default>
<&'a [T] as std::default::Default>
<[T; 22] as std::default::Default>
<[T; 7] as std::default::Default>
and 31 others
= note: required by `std::default::Default::default`
If I attempt to add the missing initializer for the array:
impl Default for [u32; 256] {
fn default() -> [u32; 255] {
[0; 256]
}
}
I get:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/lib.rs:7:5
|
7 | impl Default for [u32; 256] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference any types defined in this crate
= note: define and implement a trait or new type instead
Am I doing something wrong?
Rust does not implement Default for all arrays because it does not have non-type polymorphism. As such, Default is only implemented for a handful of sizes.
You can, however, implement a default for your type:
impl Default for Histogram {
fn default() -> Histogram {
Histogram {
sum: 0,
bins: [0; 256],
}
}
}
Note: I would contend that implementing Default for u32 is fishy to start with; why 0 and not 1? or 42? There is no good answer, so no obvious default really.
I'm afraid you can't do this, you will need to implement Default for your structure yourself:
struct Histogram {
sum: u32,
bins: [u32; 256],
}
impl Default for Histogram {
#[inline]
fn default() -> Histogram {
Histogram {
sum: 0,
bins: [0; 256],
}
}
}
Numeric types have nothing to do with this case, it's more like problems with fixed-size arrays. They still need generic numerical literals to support this kind of things natively.
If you're sure to initialize every field with zero, this would work:
impl Default for Histogram {
fn default() -> Histogram {
unsafe { std::mem::zeroed() }
}
}
Indeed, at the time of writing, support for fixed-length arrays is still being hashed out in the standard library:
https://github.com/rust-lang/rust/issues/7622

Resources