Rust lifetimes for implementing a trait on nested slices - rust

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.

Related

Building structs dynamically with lifetime parameters

Trying to build a tree structure from another tree structure in Rust - where the the built tree structure are dependent on lifetimes parameters.
The traits below represents a simplified version of my search tree structure (the one I wish for to be build dynamically):
trait SPart {
fn search<'b>(&'b self, queue: &mut Vec<Box<dyn SPart + 'b>>);
}
trait SubSPart<PP: SPart> {
fn promote_search<'b>(&'b self, parent: &'b PP, queue: &mut Vec<Box<dyn SPart + 'b>>);
}
struct SP<'a>(pub Vec<Box<dyn SubSPart<Self> + 'a>>);
struct SSP(pub i32);
impl<'a> SPart for SP<'a> {
fn search<'b>(&'b self, queue: &mut Vec<Box<dyn SPart + 'b>>) {
for c in &self.0 {
c.promote_search(self, queue);
}
}
}
impl<'a> SubSPart<SP<'a>> for SSP {
fn promote_search<'b>(&'b self, parent: &'b SP, queue: &mut Vec<Box<dyn SPart + 'b>>) {
queue.push(Box::new(SP(vec![])));
}
}
The parts and subparts can contain references to data, hence I think the lifetime-parameter is necessary.
These parts are usually also short-lived in a recursive function, and can be created dynamically referring back to data from earlier frames in the recursive call.
This all works with flying colors, so now I'm interested in building this initial tree structure dynamically from a separate tree structure:
trait BPart {
fn build<'b>(&'b self, v: &mut Vec<Box<dyn SPart + 'b>>);
}
trait SubBPart<P, PP: SPart> {
fn build<'b>(&'b self, parent: &'b P, v: &mut Vec<Box<dyn SubSPart<PP> + 'b>>);
}
struct BP<'a>(pub Vec<Box<dyn SubBPart<Self, SP<'a>>>>, pub i32);
struct SBP(pub i32);
impl<'a> BPart for BP<'a> {
fn build<'b>(&'b self, v: &mut Vec<Box<dyn SPart + 'b>>) {
let mut sv = vec![];
for sp in &self.0 {
sp.build(self, &mut sv);
}
let sp = SP(sv);
v.push(Box::new(sp));
}
}
impl<'a> SubBPart<BP<'a>, SP<'a>> for SBP {
fn build<'b>(&'b self, parent: &'b BP<'a>, v: &mut Vec<Box<dyn SubSPart<SP> + 'b>>) {
v.push(Box::new(SSP(self.0 + parent.1)));
}
}
fn main() {
let bp = BP(vec![Box::new(SBP(42))], 21);
let mut v = vec![];
bp.build(&mut v);
}
However, this fails with:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
It seems like the lifetime is tied to the BPart ('a) where I wish for the lifetime to be valid for any lifetime ('b) at the time of creation of the SPart and SubSPart, but I'm unaware of how to express this in Rust.
Link to rust playground
Edit:
Added trait methods and examples, and main method.
This is quite the spaghetti of lifetime constraints so I'll try to break down the limitations:
The lifetime 'b is invariant due to its use in &mut Vec<Box<dyn SPart + 'b>>. Most lifetime annotations are covariant, meaning it can be shortened as necessary to align with other constraints. But the compiler cannot do so here because, if shortened, the value could be mutated or assigned to a value that lives shorter than it needs to.
The lifetime 'a is invariant due to its use in Vec<Box<dyn SubBPart<Self, SP<'a>>>>. An implementor of Trait<'a> can use inner mutability and thus, for the same reasons above, cannot be covariant.
'a: 'b - The use of &'b self implies BP<'a>: 'b and thus implies 'a: 'b meaning that the lifetime of 'b cannot outlive the life of 'a.
'b: 'a - The use of dyn SubSPart<PP> + 'b normally means that the trait object is allowed to borrow from 'b but because PP is SP<'a> it is also allowed to borrow from 'a. This means that in order for 'b from SubBPart::build to line up with BPart::build, then 'a cannot outlive 'b.
To satisfy the above constraints, it must be that 'a == 'b. But 'b is part of a trait's function signature as a generic parameter, so it must be allowed to be anything.
I don't have a good recommendation for you for how to fix it since your code is very obfuscated as to what these lifetimes and trait abstractions are for.
This is indeed a case where a higher kinded lifetime is needed. Instead of locking in on a specific lifetime, giving 'a as a generic parameter in the struct BP, the use of a higher kinded lifetime can be specified as follows:
struct BP(pub Vec<Box<dyn for<'a> SubBPart<Self, SP<'a>>>>, pub i32);
To complete the answer: In my case, a SPart or SubSPart can contain references to data from its builder BPart or SubBPart. This required changes to the traits:
trait BPart<'a> {
fn build(&'a self, v: &mut Vec<Box<dyn SPart + 'a>>);
}
trait SubBPart<'a, P, PP: SPart> {
fn build(&'a self, parent: &'a P, v: &mut Vec<Box<dyn SubSPart<PP> + 'a>>);
}
and then adjusting the impls accordingly.

Is there a CloneMut trait?

An easily overlooked feature of clone() is that it can shorten the lifetimes of any references hidden inside the value being cloned. This is usually useless for immutable references, which are the only kind for which Clone is implemented.
It would, however, be useful to be able to shorten the lifetimes of mutable references hidden inside a value. Is there something like a CloneMut trait?
I've managed to write one. My question is whether there is a trait in the standard library that I should use instead, i.e. am I reinventing the wheel?
The rest of this question consists of details and examples.
Playground.
Special case: the type is a mutable reference
As a warm-up, the following is good enough when the type you're cloning is a mutable reference, not wrapped in any way:
fn clone_mut<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
See this question (where it is called reborrow()) for an example caller.
Special case: the reference type, though user-defined, is known
A more interesting case is a user-defined mutable-reference-like type. Here's how to write a clone_mut() function specific to a particular type:
struct Foo<'a>(&'a mut f32);
impl<'b> Foo<'b> {
fn clone_mut<'a>(self: &'a mut Foo<'b>) -> Foo<'a> {
Foo(self.0)
}
}
Here's an example caller:
fn main() {
let mut x: f32 = 3.142;
let mut p = Foo(&mut x);
{
let q = p.clone_mut();
*q.0 = 2.718;
}
println!("{:?}", *p.0)
}
Note that this won't compile unless q gets a shorter lifetime than p. I'd like to view that as a unit test for clone_mut().
Higher-kinded type?
When trying to write a trait that admits both the above implementations, the problem at first feels like a higher-kinded-type problem. For example, I want to write this:
trait CloneMut {
fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a>;
}
impl CloneMut for Foo {
fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a> {
Foo(self.0)
}
}
Of course that's not allowed in Rust (the Self<'a> and Self<'b> parts in particular). However, the problem can be worked around.
General case
The following code compiles (using the preceding definition of Foo<'a>) and is compatible with the caller:
trait CloneMut<'a> {
type To: 'a;
fn clone_mut(&'a mut self) -> Self::To;
}
impl<'a, 'b> CloneMut<'a> for Foo<'b> {
type To = Foo<'a>;
fn clone_mut(&'a mut self) -> Self::To {
Foo(self.0)
}
}
It's a little ugly that there is no formal relationship between Self and Self::To. For example, you could write an implementation of clone_mut() that returns 77, completely ignoring the Self type. The following two attempts show why I think the associated type is unavoidable.
Attempt 1
This compiles:
trait CloneMut<'a> {
fn clone_mut(&'a mut self) -> Self;
}
impl<'a> CloneMut<'a> for Foo<'a> {
fn clone_mut(&'a mut self) -> Self {
Foo(self.0)
}
}
However, it's not compatible with the caller, because it does not have two distinct lifetime variables.
error[E0502]: cannot borrow `*p.0` as immutable because `p` is also borrowed as mutable
The immutable borrow mentioned in the error message is the one in the println!() statement, and the mutable borrow is the call to clone_mut(). The trait constrains the two lifetimes to be the same.
Attempt 2
This uses the same trait definition as attempt 1, but a different implementation:
trait CloneMut<'a> {
fn clone_mut(&'a mut self) -> Self;
}
impl<'a, 'b: 'a> CloneMut<'a> for Foo<'b> {
fn clone_mut(&'a mut self) -> Self {
Foo(self.0)
}
}
This doesn't even compile. The return type has the longer lifetime, and can't be made from the argument, which has the shorter lifetime.
Moving the lifetime parameter onto the method declaration gives the same error:
trait CloneMut {
fn clone_mut<'a>(&'a mut self) -> Self;
}
impl<'b> CloneMut for Foo<'b> {
fn clone_mut<'a>(&'a mut self) -> Self {
Foo(self.0)
}
}
Relationship with Clone
Incidentally, notice that CloneMut<'a, To=Self> is strictly stronger than Clone:
impl<'a, T: 'a> CloneMut<'a> for T where T: Clone {
type To = Self;
fn clone_mut(&'a mut self) -> Self {
self.clone()
}
}
That's why I think "CloneMut" is a good name.
The key property of &mut references is that they are unique exclusive references.
So it's not really a clone. You can't have two exclusive references. It's a reborrow, as the source will be completely unusable as long as the "clone" is in scope.

Rust lifetime error

Can anyone tell what the lifetime error is in the following code? (simplified from my actual code) I've looked it over myself, but I can't figure out what is wrong or how to fix it. The problem comes when I try to add the Cell, but I'm not sure why.
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &'a Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar { Bar::new(&self) }
}
The compiler error is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/foo.rs:15:32
|
15 | fn get_bar(&self) -> Bar { Bar::new(&self) }
| ^^^^^^^^
First, the solution:
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar<'a> { Bar::new(&self) }
}
There are two problems in your code. The first is with get_bar, where you didn't specify the lifetime for the return type. When you don't specify lifetimes in signatures, Rust doesn't infer the correct lifetimes, it just blindly fills them in based on simple rules. In this specific case, what you get is effectively fn get_bar<'b>(&'b self) -> Bar<'b> which is obviously wrong, given the lifetime of self.raw (which was what you actually wanted) is 'a. See the Rust Book chapter on Lifetime Elision.
The second problem is that you're over-constraining the argument to Bar::new. &'a Foo<'a> means you require a borrow to a Foo for as long as the strings it's borrowing exist. But borrows within a type have to outlive values of said type, so the only lifetime valid in this case is where 'a matches the entire lifetime of the thing being borrowed... and that conflicts with the signature of get_bar (where you're saying &self won't necessarily live as long as 'a since it has its own lifetime). Long story short: remove the unnecessary 'a from the Foo borrow, leaving just &Foo<'a>.
To rephrase the above: the problem with get_bar was that you hadn't written enough constraints, the problem with Bar::new was that you'd written too many.
DK explained which constraints were missing and why, but I figured I should explain why the code was working before I added Cell. It turns out to be due to variance inference.
If you add in the inferred lifetimes to the original code and rename the lifetime variables to be unique, you get
struct Bar<'b> {
bar: &'b str,
}
impl<'b> Bar<'b> {
fn new(foo: &'b Foo<'b>) -> Bar<'b> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar<'c>(&'c self) -> Bar<'c> { Bar::new(&self) }
}
The problem comes when calling Bar::new, because you are passing &'c Foo<'a>, to something expecting &'b Foo<'b>. Normally, immutable types in Rust are covariant, meaning that &Foo<'a> is implicitly convertable to &Foo<'b> whenever 'b is a shorter lifetime than 'a. Without the Cell, &'c Foo<'a> converts to &'c Foo<'c>, and is passed to Bar::new wiht 'b = 'c, so there is no problem.
However, Cell adds interior mutability to Foo, which means that it is no longer safe to be covariant. This is because Bar could potentially try to assign a shorter lived 'b reference back into the original Foo, but Foo requires that all of the references it holds are valid for the longer lifetime 'a. Therefore, interior mutability makes &Foo invariant, meaning you can no longer shorten the lifetime parameter implicitly.

Return reference with lifetime of self

I'd like to write some code like the following:
struct Foo {
foo: usize
}
impl Foo {
pub fn get_foo<'a>(&'a self) -> &'self usize {
&self.foo
}
}
But this doesn't work, failing with invalid lifetime name: 'self is no longer a special lifetime.
How can I return a reference that lives as long as the object itself?
You don't want the reference to live exactly as long as the object. You just want a borrow on the object (quite possibly shorter than the entire lifetime of the object), and you want the resulting reference to have the lifetime of that borrow. That's written like this:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
Additionally, lifetime elision makes the signature prettier:
pub fn get_foo(&self) -> &usize {
&self.foo
}
In your example the lifetime of self is 'a so the lifetime of the returned reference should be 'a:
pub fn get_foo<'a>(&'a self) -> &'a usize {
&self.foo
}
However the compiler is able to deduce (lifetime elision) the correct lifetime in simple cases like that, so you can avoid to specify lifetime at all, this way:
pub fn get_foo(&self) -> &usize {
&self.foo
}
Look here for lifetime elision rules

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