Copying local variable into vector in Rust - rust

I'm new to Rust, and I'm trying to copy a local variable into a vector. Here's my attempt:
#[derive(Copy, Clone)]
struct DFAItem<'a> {
reading: usize,
production: &'a grammar::CFGProduction<'a>,
next_terminal: i32,
}
fn add_nonterminal<'a>(cfg: &'a grammar::CFG, nonterminal: usize, itemset: &'a mut Vec<DFAItem>) {
let productions = &cfg.productions[nonterminal];
for prod in productions {
let item = DFAItem {
reading: 0,
production: prod,
next_terminal: 0,
};
itemset.push(item); //here, I get a lifetime error (lifetime 'a required).
match prod.rhs[0] {
grammar::Symbol::Nonterminal(x) if x != nonterminal => add_nonterminal(cfg, x, itemset),
_ => (),
}
}
}
I understand that I can't modify the lifetime of item to make it match itemset, so what I'm trying to do is copy item into the vector, so that would have the vector's lifetime. Any help/tips would be appreciated.
Also, anybody know the syntax so that I could change cfg to have at least as long of a lifetime as itemset instead of the same? Would I just declare a second lifetime or is there a better way to do it?
EDIT: here are the definitions of CFG and CFGProduction:
pub enum Symbol {
Terminal(i32),
Nonterminal(usize),
}
pub struct CFGProduction<'a> {
pub nonterminal: usize,
pub rhs: &'a Vec<Symbol>,
}
pub struct CFG<'a> {
pub terminals: Vec<i32>,
pub productions: Vec<Vec<CFGProduction<'a>>>,
}

First, the lifetime of the itemset vec is not relevant and doesn't need to be constrained to anything. Second, CFG and DFAItem have generic lifetime parameters, so they should be indicated as such when using them in function arguments.
Here's my take, there's two big lifetimes involved here:
'a: the lifetime needed by CFGProduction's
'b: the lifetime of cfg and its subsequent references stored in DFAItems
Therefore, DFAItem should have two lifetimes:
struct DFAItem<'a, 'b> {
// ...
production: &'b grammar::CFGProduction<'a>,
// ...
}
and add_nonterminal()'s signature would look like so:
fn add_nonterminal<'a, 'b>(cfg: &'b grammar::CFG<'a>, nonterminal: usize, itemset: &mut Vec<DFAItem<'a, 'b>>) {
// ...
}
With these lifetime changes, the function body compiles as is. See it on the playground.
You can choose not to do that and just use 'a for everything:
struct DFAItem<'a> {
// ...
production: &'a grammar::CFGProduction<'a>,
// ...
}
fn add_nonterminal<'a>(cfg: &'a grammar::CFG<'a>, nonterminal: usize, itemset: &mut Vec<DFAItem<'a>>) {
// ...
}
but I'd advise against it. Types with the pattern &'a Type<'a>, where the generic lifetime is linked with itself can cause problems down the line; especially with mutability.

Related

How do I properly add lifetimes to an iterator containing other iterators in Rust?

I currently have code that looks kind of like this:
struct People {
names: Vec<String>,
ages: Vec<i32>,
}
impl People {
fn iter_people<'a>(&'a self) -> PeopleIterator<'a> {
return PeopleIterator {
names_iterator: Box::new(self.names.iter()),
ages: Box::new(self.ages.iter()),
};
}
}
struct PeopleIterator<'a> {
names_iterator: Box<dyn Iterator<Item = &'a String>>,
ages: Box<dyn Iterator<Item = &'a i32>>,
}
impl<'a> Iterator for PeopleIterator<'a> {
...snip...
}
I am aware that I should model a person as a struct Person and then have a Vec<Person> to model people but this is just a simplification of my actual code.
Anyway, the Rust compiler tells me this:
lifetime may not live long enough
requirement occurs because of the type PeopleIterator<'_>, which makes the generic argument '_ invariant
I have looked at the suggested link for subtyping and variance but I need to read it a few more times to actually understand it.
What stumps me is that I would expect both my iterators self.names.iter() and self.ages.iter() to live as long as self and I have declared that self should live as long as PeopleIterator. However, when I look at the iter() function, it does not make this constraint but instead has an anonymous lifetime '_. I am guessing this is the problem but I am confused and don't know how to fix it :(
The problem is the lifetime of the iterator itself in Box<dyn Iterator<Item = &'a String>> is by default bound to be 'static, but that's not possible for an iterator containing non static references like anything from &'a self. The solution is to specify an explicit lifetime bound:
struct PeopleIterator<'a> {
names_iterator: Box<dyn Iterator<Item = &'a String> + 'a>,
ages: Box<dyn Iterator<Item = &'a i32> + 'a>,
}
Personally I'd just use generics instead of static dispatch avoiding some indirection and the whole problem from the beginning:
impl People {
fn iter_people(&self) -> PeopleIterator<impl Iterator<Item = &String>, impl Iterator<Item = &i32>> {
return PeopleIterator {
names_iterator: self.names.iter(),
ages: self.ages.iter(),
};
}
}
struct PeopleIterator<N, A> {
names_iterator: N,
ages: A,
}

Rust lifetimes for implementing a trait on nested slices

I want to create a wrapper around (nested) slices for easy operations on multidimensional data, owned by a different struct.
The most basic version of the mutable version of my slice wrapper might look like this:
struct MySliceMut<'a> {
data: Vec<&'a mut [f32]>,
}
impl<'a, 'b> MySliceMut<'a> {
fn get(&'b mut self) -> &'a mut [&'b mut [f32]] {
self.data.as_mut_slice()
}
}
Now if I want to implement a trait, for instance AddAssign, Rust does not seem to infer the lifetime of &mut self from the implementing type. The compiler complains that &mut self might outlive 'a:
impl<'a> AddAssign<MySlice<'a>> for MySliceMut<'a> { // lifetime 'a
fn add_assign(&mut self, rhs: MySlice<'a>) { // lifetime '1
let a = self.get(); // lifetime may not live long enough, '1 must outlive 'a
let b = rhs.get();
// do inplace addition here
}
}
Full Code - Rust Playground
I tried to figure out the issue with the lifetimes, but can't find it. Would the trait impl require any additional annotations?
struct MySlice<'a> {
data: Vec<&'a [f32]>,
}
impl<'a, 'b> MySlice<'a> {
fn get(&'b self) -> &'a [&'b [f32]] {
self.data.as_slice()
}
}
Problem with your code is that fn get(&'b self) returns variable with wrong lifetime. Associated lifetime 'a of MySlice<'a> is lifetime of inner slice. Associated lifetime 'b of fn get(...) is lifetime of the self. So I guess the function probably should return &'b [&'a [f32]] instead.
-- Edited --
Make sure to change fn get(...) of MySliceMut either.

How to create a vector based on an `&[Box<dyn CustomTrait>]`?

I have a custom trait that I use as the element type in a slice:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: &'a [Box<dyn IConstraint>]
}
I would like to offer an add_constraint method that does a copy-on-write of the slice. Something like this:
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: Box<dyn IConstraint<TNodeState>>) {
let mut constraints: Vec<Box<dyn IConstraint<TNodeState>>> = Vec::new();
constraints.copy_from_slice(self.constraints);
constraints.push(constraint);
self.constraints = &constraints;
}
}
The problem is I get this error:
the trait bound Box<dyn IConstraint<TNodeState>>: std::marker::Copy is not satisfied
the trait std::marker::Copy is not implemented for Box<dyn IConstraint<TNodeState>>
Ok, so the Box<T> doesn't implement the Copy trait. Fair enough. But how do I address that? Ideally, I'd reuse the boxes or at least the constraints because they are immutable. But if I can't do that due to rust ownership rules, how can I implement the Copy trait on a box type? I've tried various ways and they all produce errors.
This attempt produces "Copy not allowed on types with destructors":
impl<TNodeState> Copy for Box<dyn IConstraint<TNodeState>> {
}
What about Clone? I can switch to constraints.clone_from_slice(self.constraints);, but then implementing the Clone trait on IConstraint produces a bunch of "IConstraint cannot be made into an object" errors.
Even if I could get box to be cloneable, then of course I get the anticipated borrow lifetime flaw from my add_constraint method:
borrowed value does not live long enough
So do I have to throw out my add_constraint function idea altogether and force the owner of my struct to manually copy it? Given my actual struct contains 3 fields, that gets tedious as the owner now has to deconstruct the fields into locals in order to drop the immutable borrow, allowing the original vector to be mutated:
fn add_remove_constraint() {
let mut scenario = Scenario::<&str, bool, 3_usize>::new(&["A", "B", "C"]);
let mut constraints: Vec<Box<dyn IConstraint<bool>>> = Vec::new();
constraints.push(Box::new(SelectionCountConstraint {
nodes: [1, 2],
min: 1,
max: 2,
}));
scenario = Scenario {
constraints: &constraints,
..scenario
};
assert_eq!(1, scenario.get_constraints().len());
let nodes = scenario.nodes;
let selection_state = scenario.selection_state;
constraints.pop();
scenario = Scenario {
constraints: &constraints,
nodes,
selection_state,
};
assert_eq!(0, scenario.get_constraints().len());
}
I think you got it all wrong. As said in the comments, your add_constraint will never work, because you are referencing something you create in the same function in the first place (which will be dropped after the function scope expires).
You should own a container over those IConstraint trait, but inside you should have an &dyn IConstraint or Box<dyn IConstraint>.
Adding an item to them is trivial in that case:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: Vec<&'a dyn IConstraint>
}
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: &'a dyn IConstraint) {
self.constraints.push(constraint);
}
}
Playground
This should solve your problem since references are Copy.

Using a struct containing a borrowed parameter

I'm writing a simple game in Rust, which includes a Drawer, which is constructed once and then passed through many methods as a mutable reference:
pub struct Drawer<'a> {
// ...
renderer: Renderer<'a>,
// ...
}
fn pause(drawer: &mut Drawer, events: &[Event]) {
// ...
drawer.draw_text(&TextPos::Centered, "Paused", 1);
// ...
}
I wanted to refactor my code to introduce a fluent interface for drawing text, such as:
drawer.text()
.size(4)
.centered()
.draw("Paused");
I did this by creating a TextDrawer struct, that contains a reference to the Drawer:
pub struct TextDrawer<'a, 'b: 'a> {
pos: TextPos,
size: u32,
drawer: &'a mut Drawer<'b>,
}
impl<'a> Drawer<'a> {
pub fn text(&mut self) -> TextDrawer {
TextDrawer {
pos: TextPos::At(0, 0),
size: 1,
drawer: self,
}
}
}
I think the lifetimes I've put on the struct are correct (the reference must last as long as the Drawer itself).
However, my text method will not compile until I add explicit lifetimes. When I do, every method that calls text then demands explicit lifetimes, and so on. I'm surprised these lifetimes have to be stated: after all, they're all of the form fn foo<'a, 'b: 'a>(drawer: &mut'a Drawer<'b>). I had assumed before this point that this was already the inferred lifetime, since it was always necessary for the reference to last as long as the Drawer itself.
Is it necessary for me to put these explicit lifetimes all other my method signatures? Or can I avoid it in some other way?
Thanks to the minimal example made by Lukas above, I realised I had simply got the lifetime parameters to my text method backwards.
My incorrect lifetimes:
impl<'a> Drawer<'a> {
pub fn text<'b>(&'b mut self) -> TextDrawer<'a, 'b> {
// omitted
}
}
The correct lifetimes:
impl<'a> Drawer<'a> {
pub fn text<'b>(&'b mut self) -> TextDrawer<'b, 'a> {
// omitted
}
}
After this, everything compiles without any further explicit lifetimes.

Tying a trait lifetime variable to &self lifetime

I'd like to do something along the following lines:
trait GetRef<'a> {
fn get_ref(&self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a> GetRef<'a> for Foo<'a> {
fn get_ref(&self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// this is the part I'm struggling with:
impl <'a> GetRef<'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
The point of the explicit lifetime variable in the GetRef trait is to allow the return value of get_ref() on a Foo object to outlive the Foo itself, tying the return value's lifetime to that of the lifetime of Foo's buffer.
However, I haven't found a way to implement GetRef for Bar in a way that the compiler accepts. I've tried several variations of the above, but can't seem to find one that works. Is there any there any reason that this fundamentally cannot be done? If not, how can I do this?
Tying a trait lifetime variable to &self lifetime
Not possible.
Is there any there any reason that this fundamentally cannot be done?
Yes. An owning vector is something different than a borrowed slice. Your trait GetRef only makes sense for things that already represent a “loan” and don't own the slice. For an owning type like Bar you can't safely return a borrowed slice that outlives Self. That's what the borrow checker prevents to avoid dangling pointers.
What you tried to do is to link the lifetime parameter to the lifetime of Self. But the lifetime of Self is not a property of its type. It just depends on the scope this value was defined in. And that's why your approach cannot work.
Another way of looking at it is: In a trait you have to be explicit about whether Self is borrowed by a method and its result or not. You defined the GetRef trait to return something that is not linked to Self w.r.t. lifetimes. So, no borrowing. So, it's not implementable for types that own the data. You can't create a borrowed slice referring to a Vec's elements without borrowing the Vec.
If not, how can I do this?
Depends on what exactly you mean by “this”. If you want to write a “common denominator” trait that can be implemented for both borrowed and owning slices, you have to do it like this:
trait GetRef {
fn get_ref(&self) -> &[u8];
}
The meaning of this trait is that get_ref borrows Self and returns a kind of “loan” because of the current lifetime elision rules. It's equivalent to the more explicit form
trait GetRef {
fn get_ref<'s>(&self) -> &'s [u8];
}
It can be implemented for both types now:
impl<'a> GetRef for Foo<'a> {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
impl GetRef for Bar {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
You could make different lifetimes for &self and result in your trait like that:
trait GetRef<'a, 'b> {
fn get_ref(&'b self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a, 'b> GetRef<'a, 'b> for Foo<'a> {
fn get_ref(&'b self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// Bar, however, cannot contain anything that outlives itself
impl<'a> GetRef<'a, 'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
}
fn main() {
let a = vec!(1 as u8, 2, 3);
let b = a.clone();
let tmp;
{
let x = Foo{buf: &a};
tmp = x.get_ref();
}
{
let y = Bar{buf: b};
// Bar's buf cannot outlive Bar
// tmp = y.get_ref();
}
}

Resources