Generic parameter with reference used as function pointer argument - rust

I am having trouble figuring out what lifetime parameter will work for this, so my current workarounds include transmutes or raw pointers. I have a structure holding a function pointer with a generic as a parameter:
struct CB<Data> {
cb: fn(Data) -> usize
}
I would like to store an instance of that, parameterized by some type containing a reference, in some other structure that implements a trait with one method, and use that trait method to call the function pointer in CB.
struct Holder<'a> {
c: CB<Option<&'a usize>>
}
trait Exec {
fn exec(&self, v: &usize) -> usize;
}
impl<'a> Holder<'a> {
fn exec_aux(&self, v: &'a usize) -> usize {
(self.c.cb)(Some(v))
}
}
impl<'a> Exec for Holder<'a> {
fn exec(&self, v: &usize) -> usize
{
self.exec_aux(v)
}
}
This gives me a lifetime error for the 'Exec' impl of Holder:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
Simply calling exec_aux works fine as long as I don't define that Exec impl:
fn main() {
let h = Holder { c: CB{cb:cbf}};
let v = 12;
println!("{}", h.exec_aux(&v));
}
Also, making CB not generic also makes this work:
struct CB {
cb: fn(Option<&usize>) -> usize
}
The parameter in my actual code is not a usize but something big that I would rather not copy.

The lifetimes in your Exec trait are implicitly this:
trait Exec {
fn exec<'s, 'a>(&'s self, v: &'a usize) -> usize;
}
In other words, types that implement Exec need to accept any lifetimes 's and 'a. However, your Holder::exec_aux method expects a specific lifetime 'a that's tied to the lifetime parameter of the Holder type.
To make this work, you need to add 'a as a lifetime parameter to the Exec trait instead, so that you can implement the trait specifically for that lifetime:
trait Exec<'a> {
// ^^^^ vv
fn exec(&self, v: &'a usize) -> usize;
}
impl<'a> Exec<'a> for Holder<'a> {
// ^^^^ vv
fn exec(&self, v: &'a usize) -> usize
{
self.exec_aux(v)
}
}

The problem here is that the Exec trait is too generic to be used in this way by Holder. First, consider the definition:
trait Exec {
fn exec(&self, v: &usize) -> usize;
}
This definition will cause the compiler to automatically assign two anonymous lifetimes for &self and &v in exec. It's basically the same as
fn exec<'a, 'b>(&'a self, v: &'b usize) -> usize;
Note that there is no restriction on who needs to outlive whom, the references just need to be alive for the duration of the method call.
Now consider the definition
impl<'a> Holder<'a> {
fn exec_aux(&self, v: &'a usize) -> usize {
// ... doesn't matter
}
}
Since we know that &self is a &Holder<'a> (this is what the impl refers to), we need to have at least a &'a Holder<'a> here, because &'_ self can't have a lifetime shorter than 'a in Holder<'a>. So this is saying that the two parameters have the same lifetime: &'a self, &'a usize.
Where it all goes wrong is when you try to combine the two. The trait forces you into the following signature, which (again) has two distinct implicit lifetimes. But the actual Holder which you then try to call a method on forces you to have the same lifetimes for &self and &v.
fn exec(&self, v: &usize) -> usize {
// Holder<'a> needs `v` to be `'a` when calling exec_aux
// But the trait doesn't say so.
self.exec_aux(v)
}
One solution is to redefine the trait as
trait Exec<'a> {
fn exec(&'a self, v: &'a usize) -> usize;
}
and then implement it as
impl<'a> Exec<'a> for Holder<'a> {
fn exec(&'a self, v: &'a usize) -> usize {
self.exec_aux(v)
}
}

Related

Can a trait's impl specify a lifetime that comes from a method's input argument?

For a type
pub struct Child<'a> {
buf: &'a mut [u8],
}
I can define a trait and implement the trait for the type but with a lifetime that is bound to a calling function's context (not to a local loop context):
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
And first to show a somewhat working example because x is only borrowed within the context of the loop because Child::make_mut is hardcoded in the map1 function:
pub fn map1<F>(mut func: F)
where
F: FnMut(&mut Child),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = Child::make_mut(s);
func(&mut w);
}
}
But in trying to make map2, a generic version of map1 where the T is bound to the MakeMut trait but with lifetime of the entire function body, this won't compile, for good reasons (the T lifetimes that would be created by T: MakeMut<'a> have the lifetime of map2, not the inner loop):
pub fn map2<'a, F, T>(mut func: F) // lifetime `'a` defined here
where
T: MakeMut<'a>,
F: FnMut(&mut T),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = T::make_mut(s); // error: argument requires that `*x` is borrowed for `'a`
func(&mut w);
}
}
I want to do something almost like this but of course it doesn't compile either:
pub trait MakeMut {
fn make_mut<'a>(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self { // lifetime mismatch
Self{ buf }
}
}
with the compiler errors:
error[E0308]: method not compatible with trait
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut [u8]) -> Child<'_>`
found fn pointer `fn(&'a mut [u8]) -> Child<'_>`
note: the lifetime `'a` as defined here...
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
--> src/main.rs:44:6
|
44 | impl<'a> MakeMut for Child<'a> {
| ^^
Is there a syntax that allows a trait for a Child<'a> where the 'a is defined by the input argument to the method make_mut? So a generic function could be defined for a trait that returns an instance but where the instance lifetime is not the entire function, but just a shorter lifetime defined by an inner block?
I understand the lifetime is part of the type being returned, but it almost seems like a higher-ranked trait bound (HRTB) would suite this problem except I haven't found a way to specify the lifetime that suites the trait and the method signatures.
Here is a playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fb28d6da9d89fde645edeb1ca0ae5b21
Your first attempt is close to what you want. For reference:
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
The first problem is the bound on T in map2:
pub fn map2<'a, F, T>(mut func: F)
where
T: MakeMut<'a>,
F: FnMut(&mut T),
This requires the compiler to deduce a single 'a that applies for the whole function. Since lifetime parameters come from outside of the function, the lifetime 'a is necessarily longer than the function invocation, which means anything with lifetime 'a has to outlive the function. Working backwards from the T::make_mut() call, the compiler eventually deduces that x is &'a mut Vec<_> which means vec has to outlive the function invocation, but there's no possible way it can since it's a local.
This can be fixed by using a higher-rank trait bound indicating that T has to implement MakeMut<'a> for any possible lifetime 'a, which is expressed like this:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: FnMut(&mut T),
With this change, the code compiles.
What you'll then find is that you can't ever actually call map2 with T=Child<'_> because you'll run into the same problem in a different place. The caller must specify a specific lifetime for 'a in Child<'a>, but this disagrees with the HRTB -- you have impl<'a> MakeMut<'a> for Child<'a> but the HRTB wants impl<'a, 'b> MakeMut<'b> for Child<'a>, and that brings back the lifetime problem in that implementation's make_mut.
One way around this is to decouple the implementation of MakeMut from Child, providing a "factory type" that uses associated types. This way, the caller doesn't have to supply any pesky lifetime argument that could cause trouble later.
pub trait MakeMut<'a> {
type Item;
fn make_mut(buf: &'a mut [u8]) -> Self::Item;
}
struct ChildFactory;
impl<'a> MakeMut<'a> for ChildFactory {
type Item = Child<'a>;
fn make_mut(buf: &'a mut [u8]) -> Child<'a> {
Child { buf }
}
}
Then we modify map2 to be aware of the associated type:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: for<'a, 'b> FnMut(&'b mut <T as MakeMut<'a>>::Item),
whew
Now, finally, we can use map2:
map2::<_, ChildFactory>(|v| {});
(Playground)

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.

How do you write a trait that returns an iterator?

Broadly speaking my goal is this:
For some known type Bar...
Have a trait Foo with a function: get_iterator<T>() -> T where T: Iterator<Item = Bar>
The instance of the iterator borrows the original object Foo is implemented on.
I imagine it working like this:
let mut foo = Foo;
let bar = foo.get_iterator();
foo.mutable_call(); // <-- This fails, because foo is borrowed in bar
for x in bar {
...
}
So, that's the goal, and here's my attempt, which I can't seem to get working:
struct ValsFromT<'a, T: 'a> {
parent:&'a T,
offset: usize,
}
struct Val;
trait HasValsIterator<T> {
fn val_iterator(&self) -> T where T: Iterator<Item = Val>;
}
struct Foo;
impl<'a> Iterator for ValsFromT<'a, Foo> {
type Item = Val;
fn next(&mut self) -> Option<Val> {
return None;
}
}
impl<'a> HasValsIterator<ValsFromT<'a, Foo>> for Foo {
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
return ValsFromT {
offset: 0usize,
parent: self
};
}
}
fn takes_vals<T>(instance:T) where T: HasValsIterator<T> {
// ...
}
#[test]
fn test_foo() {
let x = Foo;
takes_vals(x);
}
(playpen: http://is.gd/wys3fx)
We're getting the dreaded concrete/bound lifetime error here, because of trying to return an iterator instance that references self from the trait function:
<anon>:22:3: 27:4 error: method `val_iterator` has an incompatible type for trait:
expected bound lifetime parameter ,
found concrete lifetime [E0053]
<anon>:22 fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
<anon>:23 return ValsFromT {
<anon>:24 offset: 0usize,
<anon>:25 parent: self
<anon>:26 };
<anon>:27 }
<anon>:22:3: 27:4 help: see the detailed explanation for E0053
Is there some way of doing this?
Unfortunately, Veedrac's suggestion doesn't work directly. You will get the following error if you'd try to use val_iterator() method on instance inside takes_vals():
<anon>:31:25: 31:39 error: the trait `core::iter::Iterator` is not implemented for the type `U` [E0277]
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~~~~~~~
<anon>:31:25: 31:39 help: see the detailed explanation for E0277
<anon>:31:25: 31:39 note: `U` is not an iterator; maybe try calling `.iter()` or a similar method
error: aborting due to previous error
playpen: application terminated with error code 101
This (and some other further errors) requires changing the signature of the function to this one:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U>
However, even this doesn't work yet:
<anon>:31:16: 31:24 error: `instance` does not live long enough
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~
<anon>:30:97: 32:2 note: reference must be valid for the lifetime 'a as defined on the block at 30:96...
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
<anon>:30:97: 32:2 note: ...but borrowed value is only valid for the scope of parameters for function at 30:96
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
Remember that the trait requires that val_iterator() accepts the target by reference with lifetime 'a. This lifetime in this function is an input parameter. However, when val_iterator() is called on instance, the only lifetime which can be specified for the reference is the one of instance which is strictly smaller than any possible 'a as a parameter, because it is a local variable. Therefore, it is not possible to pass instance by value; you can only pass it by reference for lifetimes to match:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: &'a T) where T: HasValsIterator<'a, U> {
let iter = instance.val_iterator();
}
This works.
I'd like to add that using associated types instead of type parameters would be more correct semantically:
trait HasValsIterator<'a> {
type Iter: Iterator<Item=Val> + 'a;
fn val_iterator(&'a self) -> Self::Iter;
}
impl<'a> HasValsIterator<'a> for Foo {
type Iter = ValsFromT<'a, Foo>;
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> { ... }
}
fn takes_vals<'a, T: 'a>(instance: &'a T) where T: HasValsIterator<'a> {
...
}
I say that this is more correct because the type of the iterator is determined by the implementor, that is, it is "output" type, which are modeled by associated types. As you can see, takes_vals() signature also shrank considerably.
Ideally, HasValsIterator trait should have been defined like this:
trait HasValsIterator {
type Iter<'a>: Iterator<Item=Val> + 'a
fn val_iterator<'a>(&'a self) -> Iter<'a>;
}
This way, val_iterator() would in any situation, including when HasValsIterator implementor is passed by value. However, Rust is not there yet.

What does it mean for a trait to have a lifetime parameter?

I understand how lifetime parameters apply to functions and structs, but what does it mean for a trait to have a lifetime parameter? Is it a shortcut to introduce a lifetime parameter to its methods, or is it something else?
If you have a trait with a lifetime bound, then implementors of the trait can participate in the same lifetime. Concretely, this allows you to store references with that lifetime. It is not a shortcut for specifying lifetimes on member methods, and difficulty and confusing error messages lie that way!
trait Keeper<'a> {
fn save(&mut self, v: &'a u8);
fn restore(&self) -> &'a u8;
}
struct SimpleKeeper<'a> {
val: &'a u8,
}
impl<'a> Keeper<'a> for SimpleKeeper<'a> {
fn save(&mut self, v: &'a u8) {
self.val = v
}
fn restore(&self) -> &'a u8 {
self.val
}
}
Note how both the struct and the trait are parameterized on a lifetime, and that lifetime is the same.
What would the non-trait versions of save() and restore() look like for SimpleKeeper<'a>?
Very similar, actually. The important part is that the struct stores the reference itself, so it needs to have a lifetime parameter for the values inside.
struct SimpleKeeper<'a> {
val: &'a u8,
}
impl<'a> SimpleKeeper<'a> {
fn save(&mut self, v: &'a u8) {
self.val = v
}
fn restore(&self) -> &'a u8 {
self.val
}
}
And would they mean exactly the same thing as the the trait version?
Yep!

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