Using a struct containing a borrowed parameter - rust

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.

Related

Lifetime gets smaller after extracting method

I had a lifetime problem on extracting a method in Rust. Following is a minimal example:
pub struct Obj {
value: usize,
}
pub struct Container<'a> {
content: &'a Obj,
}
pub struct Props<'a> {
att: Container<'a>,
}
impl <'a> Props<'a> {
pub fn value(&self) -> usize {
self.att.content.value
}
}
This works fine with:
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
|| properties.att.content.value
}
but gives an error for:
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
|| properties.value()
}
closure may outlive the current function, but it borrows 'properties', which is owned by the current function
I think I understand this error message, but I do not understand why the first piece of code does compile. Isn't properties borrowed also in the first example?
Could this problem be solved by putting some lifetimes to the function value()?
Link to Rust Playground Example
Since edition 2021 closures are allowed to borrow only part of a struct so your first example is allowed to borrow only part of it namely properties.att.content.value which is behind a reference of appropriate lifetime for the closure you're returning.
The second example does not see it only needs that part so it has to borrow the full properties, but that is dropped at the end of the function, so you can't return a closure referencing it.
To make the second example work just follow the compilers recommendation, add a move before the closure, that moves properties inside the closure so it can safely be returned.
pub fn test<'a>(properties: Props<'a>) -> impl (Fn() -> usize) + 'a {
move || properties.value()
}

Copying local variable into vector in 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.

How can I return a reference wrapped by `Option` by implementing `Deref` in Rust?

I have a wrapper struct which stores an Option field. I would like to get a reference to the data stored in this field. The following code compiles.
struct Wrapper {
val: Option<i32>
}
impl Wrapper {
// lifetime specifier elided because Rust compiler can infer it
// to be fn my_deref<'a>(&'a self) -> Option<&'a i32>
fn my_deref(&self) -> Option<&i32> {
self.val.as_ref()
}
}
However, I prefer implementing Deref trait for Wrapper, so that I can have dereference coercion which is very nice. I tried the following code but the compiler complains.
use std::ops::Deref;
struct Wrapper {
val: Option<i32>
}
impl Deref for Wrapper {
type Target = Option<&i32>; // It tells me I need a lifetime specifier.
fn deref(&self) -> Option<&i32> {
self.val.as_ref()
}
}
I then tried to add a lifetime specifier, but failed again.
use std::ops::Deref;
struct Wrapper<'a> { // It tells me 'a is never used.
val: Option<i32>
}
impl<'a> Deref for Wrapper<'a> {
type Target = Option<&'a i32>;
fn deref(&'a self) -> Option<&'a i32> {
self.val.as_ref()
}
}
What is the correct way to implement deref that does the same thing as my_deref?
After reading turbulencetoo's comment, I come up with the following code, which does exactly what I intend. By program logic the Option field will never be None, so I can safely unwrap it. I must use Option to wrap it for some other reason irrelevant to this topic.
use std::ops::Deref;
struct Wrapper {
val: Option<i32>
}
impl Deref for Wrapper {
type Target = i32;
fn deref(&self) -> &i32 {
self.val.as_ref().unwrap()
}
}
Quoting turbulencetoo's comment below.
Implementing Deref for T does not mean that you can get a U from a T! It means that you can get an &U from an &T. In this case, the new Option that is created by the as_ref call in the deref function is not the same Option that your Wrapper stores, and as such you can't return a reference to it.

Is there a way to omit the lifetimes for the trait here?

I'm fighting with lifetimes again. Or actually, I kinda won the fight but I'm not sure if the outcome is the intended way to handle it.
Say I have a struct with two lifetimes: Inner<'a, 'b>. Now I want to write a trait that defines a new(inner: &Inner) -> Self method. The implementer should be free to store the reference to Inner internally and define other methods to work on it.
I came up with this (it works!) but I have a couple of questions
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker<'inner, 'a:'inner, 'b:'inner> {
inner: &'inner Inner<'a, 'b>
}
impl<'data, 'a, 'b> Worker<'data, 'a, 'b> for SomeWorker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self {
SomeWorker {
inner: inner
}
}
}
fn main () {
}
Playpen: http://is.gd/A3ol4w
in terms of lifetimes, can this be simplified? In particular, I was wondering if the trait really needs to define all those lifetimes or if there's a way to only define them on the struct?
if there's no way to omit the lifetimes on the trait does that mean it's a best practice to specify all possible lifetimes on a trait to have the most flexibility for the implementer? I mean, if the SomeWorker struct would not want to store the reference to Inner, the whole thing, including the trait, could be much simpler.
See, no lifetimes at all.
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker {
fn new (inner: &Inner) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker;
impl Worker for SomeWorker {
fn new (inner: &Inner) -> Self {
SomeWorker
}
}
fn main () {
}
Playpen: http://is.gd/NzigjX
This is why I'm asking myself if as a trait author I should assume that all methods that take references may end up being stored on a field by the trait implementer and therefore I need to specify all the lifetimes on the trait to make that possible for implementors.
There is no one-size-fits-all solution. As a trait author, you have to think about what you are attempting to do and what you want to achieve.
If you want the ability to correlate a values lifetime with the lifetime parameters of a struct, then you must put the lifetime on the trait. This would generally be done because your trait has multiple methods that are expected to operate on the same value with lifetimes. This might something like a getter / setter pair. In some code I have written, I'm passing in &str references that I hold onto for a while before "finalizing" them. If you need to store the reference for any reason, then you will need to have lifetimes on the trait.
In your case, you have a constructor method that needs to know of the lifetimes if the struct does. You can separate that function from the rest of the trait, if it's truly distinct. In your example, the work_with_inner method doesn't accept a self argument, so that would be very distinct. If you used self but didn't need to interact with the lifetimes from Inner, it can still help:
trait WorkerBuilder<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> Self;
}
trait Worker {
fn do_work(&self);
}
#[derive(Debug)]
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str,
}
// This does track `Inner`
#[derive(Debug)]
struct SomeWorker<'a, 'b>(Inner<'a, 'b>);
impl<'a, 'b> WorkerBuilder<'a, 'b> for SomeWorker<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> SomeWorker<'a, 'b> {
SomeWorker(inner)
}
}
impl<'a, 'b> Worker for SomeWorker<'a, 'b> {
fn do_work(&self) { println!("Doing work, {:?}", self.0) }
}
// This doesn't track `Inner`
#[derive(Debug)]
struct DumbWorker;
impl<'a, 'b> WorkerBuilder<'a, 'b> for DumbWorker {
fn new(inner: Inner<'a, 'b>) -> DumbWorker {
DumbWorker
}
}
fn main () {}
You'll see I also applied one thing that you can do to reduce the number of lifetimes. If you have a struct that is just references (or references and other small Copy types), there is no need to pass a reference to that struct. References are copyable, and tracking the lifetime of the containing struct isn't useful.
Editorial — I don't feel like "constructor" methods are generally useful in a trait. You often want to provide a different set or parameters, which is why you have different types in the first place. Perhaps your real code is using something other than a constructor in the trait though.

Can you control borrowing a struct vs borrowing a field?

I'm working on a program involving a struct along these lines:
struct App {
data: Vec<u8>,
overlay: Vec<(usize, Vec<u8>)>,
sink: Sink,
}
In brief the data field holds some bytes and overlay is a series of byte sequences to be inserted at specific indices. The Sink type is unimportant except that it has a function like:
impl Sink {
fn process<'a>(&mut self, input: Vec<&'a [u8]>) {
// ...
}
}
I've implemented an iterator to merge the information from data and overlay for consumption by Sink.
struct MergeIter<'a, 'b> {
data: &'a Vec<u8>,
overlay: &'b Vec<(usize, Vec<u8>)>,
// iterator state etc.
}
impl<'a, 'b> Iterator for MergeIter<'a, 'b> {
type Item = &'a [u8];
// ...
}
This is I think a slight lie, because the lifetime of each &[u8] returned by the iterator isn't always that of the original data. The data inserted from overlay has a different lifetime, but I don't see how I can annotate this more accurately. Anyway, the borrow checker doesn't seem to mind - the following approach works:
fn merge<'a, 'b>(data: &'a Vec<u8>, overlay: &'b Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&'a [u8]> {
MergeIter::new(data, overlay, start).collect()
}
impl App {
fn process(&mut self) {
let merged = merge(&self.data, &self.overlay, 0);
// inspect contents of 'merged'
self.sink.process(merged);
}
}
I end up using this merge function all over the place, but always against the same data/overlay. So I figure I'll add an App::merge function for convenience, and here's where the problem begins:
impl App {
fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {
MergeIter::new(&self.data, &self.overlay, start).collect()
}
fn process(&mut self) {
let merged = self.merge(0);
// inspect contents of 'merged'
self.sink.process(merged);
}
}
App::process now fails to pass the borrow checker - it refuses to allow the mutable borrow of self.sink while self is borrowed.
I've wrestled with this for some time, and if I've understood correctly the problem isn't with process but with this signature:
fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {
Here I've essentially told the borrow checker that the references returned in the vector are equivalent to the self borrow.
Even though I feel like I've now understood the problem, I still feel like my hands are tied. Leaving the lifetime annotations out doesn't help (because the compiler does the equivalent?), and with only the two references involved there's no way I can see to tell rust that the output reference has a lifetime bound to something else.
I also tried this:
fn merge<'a, 'b>(&'b self, start: usize) -> Vec<&'a [u8]> {
let data: &'a Vec<u8> = &self.data;
MergeIter::new(&self.data, &self.overlay, start).collect()
}
but the compiler complains about the let statement ("unable to infer appropriate lifetime due to conflicting requirements" -- I also find it infuriating that the compiler doesn't explain said requirements).
Is it possible to achieve this? The Rust Reference is kind of light on lifetime annotations and associated syntax.
rustc 1.0.0-nightly (706be5ba1 2015-02-05 23:14:28 +0000)
As long as the method merge takes &self, you cannot accomplish what you desire: it borrows all of each of its arguments and this cannot be altered.
The solution is to change it so that it doesn’t take self, but instead takes the individual fields you wish to be borrowed:
impl App {
...
fn merge(data: &Vec<u8>, overlay: &Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&[u8]> {
MergeIter::new(data, overlay, start).collect()
}
fn process(&mut self) {
let merged = Self::merge(&self.data, &self.overlay, 0);
... // inspect contents of 'merged'
self.sink.process(merged);
}
}
Yes, you've guessed correctly - the error happens because when you have merge method accept &self, the compiler can't know at its call site that it uses only some fields - merge signature only tells it that the data it returns is somehow derived from self, but it doesn't tell how - and so the compiler assumes the "worst" case and prevents you from accessing other fields self has.
I'm afraid there is no way to fix this at the moment, and I'm not sure there ever will be any. However, you can use macros to shorten merge invocations:
macro_rules! merge {
($this:ident, $start:expr) => {
MergeIter::new(&$this.data, &$this.overlay, $start).collect()
}
}
fn process(&mut self) {
let merged = merge!(self, 0);
// inspect contents of 'merged'
self.sink.process(merged);
}

Resources