Implement From with multiple type parameters - rust

I was playing around the visitor design pattern in Rust. My initial visitor didn't have any type parameter so I was able to do something like this:
impl<T> From<T> for Box<dyn VisitorElement>
where
T: VisitorElement + 'static,
{
fn from(elem: T) -> Box<dyn VisitorElement> {
Box::new(elem)
}
}
As my visitor was simply a f32 calculator, I wanted to make it more generic by replacing f32 by a type parameter. After passing the proper type parameter everywhere, my From implementation wouldn't work. Here's a complete example (playground):
/*
* Visitor traits
*/
trait Visitor<T> {
fn visit_literal(&mut self, literal: &Literal<T>);
}
trait VisitorElement<T> {
fn accept(&self, visitor: &mut dyn Visitor<T>);
}
/*
* Literal value
*/
struct Literal<T> {
value: T,
}
impl<T> Literal<T> {
fn new(value: T) -> Self {
Self { value: value }
}
}
impl<T> VisitorElement<T> for Literal<T> {
fn accept(&self, visitor: &mut dyn Visitor<T>) {
visitor.visit_literal(self)
}
}
impl<K, T> From<K> for Box<dyn VisitorElement<T>>
where
K: VisitorElement<T> + 'static,
{
fn from(elem: K) -> Box<dyn VisitorElement<T>> {
Box::new(elem)
}
}
fn main() {
let element = Literal::new(0.1);
let boxed: Box<dyn VisitorElement<_>> = element.into();
}
error[E0119]: conflicting implementations of trait `std::convert::From<std::boxed::Box<(dyn VisitorElement<_> + 'static)>>` for type `std::boxed::Box<(dyn VisitorElement<_> + 'static)>`:
--> src/main.rs:28:1
|
28 | / impl<K, T> From<K> for Box<dyn VisitorElement<T>>
29 | | where
30 | | K: VisitorElement<T> + 'static,
31 | | {
... |
34 | | }
35 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
= note: downstream crates may implement trait `VisitorElement<_>` for type `std::boxed::Box<(dyn VisitorElement<_> + 'static)>`
My goal was to allow auto boxing dynamic types in order to make code typing less verbose.
From How is there a conflicting implementation of `From` when using a generic type?, I can see that the type S can cause the trait to convert to itself but in my case the type K is constrained to VisitorElement but I stille end up with a conflict with a Box<dyn VisitorElement<_> + 'static>.
Is there a reason why the constraint on K: VisitorElement<T> + 'static allows a Box<dyn VisitorElement<T> + 'static> into itself but K: VisitorElement<f32> doesn't?
From my understanding, the type K can't be a Box because Box doesn't implement VisitorElement<T>, so I should never end up with a Box as K.
If the issue was caused by the Into being automatically implemented... I'd have From> for Literal<_> then Literal<_> into Box<dyn VisitorElement<_>, but that's true for any type. In my case it doesn't explicitly do that, unless the Box is a special type that implements the same trait as its content?

Related

How to create a recursive queue?

I am trying to implement a recursive queue using the trait Element<T> as a container for all the functions of the different nodes of the queue and two structs implementing it called Node<T> and End.
The Node<T> struct is supposed to handle all the functionality within the queue itself and the End struct's purpose is to deal with the case of the last node.
I've got the following code:
trait Element<T> {
fn append_item(self, item: T) -> Node<T>;
}
struct Node<T> {
data: T,
successor: Box<dyn Element<T>>
}
impl<T> Element<T> for Node<T> {
fn append_item(mut self, item: T) -> Node<T> {
self.successor = Box::new(self.successor.append_item(item));
self
}
}
struct End;
impl<T> Element<T> for End {
fn append_item(self, item: T) -> Node<T> {
Node { data: item, successor: Box::new(self) }
}
}
The problem is, that I get two errors:
Cannot move a value of type dyn Element<T>
The parameter type T may not live long enough
both on the same line in Node::append_item.
Now, I get why the first error occurs (because the size of dyn Element<T> cannot be statically determined) but I don't know how to work around it and I have no idea why the second error occurs.
error[E0161]: cannot move a value of type `dyn Element<T>`
--> src/lib.rs:12:35
|
12 | self.successor = Box::new(self.successor.append_item(item));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the size of `dyn Element<T>` cannot be statically determined
The issue here is that fn append_item(self, item: T) takes self by value, but in this case self has type dyn Element<T>, which is unsized and can therefore never be passed by value.
The easiest solution here is to just take self: Box<Self> instead. This means that this method is defined on a Box<E> instead of directlThis will work perfectly fine with trait objects like dyn Element<T>, and it does not require the type to be sized.
(Additionally, in the updated code below, I've changed the return type to Box<Node<T>> for convenience, but this is not required per se, just a bit more convenient.)
trait Element<T> {
fn append_item(self: Box<Self>, item: T) -> Box<Node<T>>;
}
impl<T> Element<T> for Node<T> {
fn append_item(mut self: Box<Self>, item: T) -> Box<Node<T>> {
self.successor = self.successor.append_item(item);
self
}
}
impl<T> Element<T> for End {
fn append_item(self: Box<Self>, item: T) -> Box<Node<T>> {
Box::new(Node { data: item, successor: self })
}
}
[Playground link]
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:12:26
|
12 | self.successor = Box::new(self.successor.append_item(item));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
The issue here is that dyn Trait has an implicit lifetime. In reality, it's dyn '_ + Trait. What exactly that lifetime is depends on the context, and you can read the exact rules in the Rust reference, but if neither the containing type nor the trait itself has any references, then the lifetime will always be 'static.
This is the case with Box<dyn Element<T>>, which really is Box<dyn 'static + Element<T>>. In other words, whatever type is contained by the Box must have a 'static lifetime. For this to be the case for Node<T>, it must also be that T has a 'static lifetime.
This is easy to fix, though: just follow the compiler's suggestion to add a T: 'static bound:
impl<T: 'static> Element<T> for Node<T> {
// ^^^^^^^^^
// ...
}
[Playground link)
Frxstrem already elaborated how to get around the need to move by using Box<Self> as receiver. If you need more flexibility in the parameter type (i.e. be able to hold on to references as well as owned types) instead of requiring T: 'static you can introduce a named lifetime:
trait Element<'a, T: 'a> {
fn append_item(self: Box<Self>, item: T) -> Node<'a, T>;
}
struct Node<'a, T: 'a> {
data: T,
successor: Box<dyn Element<'a, T> + 'a>,
}
impl<'a, T: 'a> Element<'a, T> for Node<'a, T> {
fn append_item(self: Box<Self>, new_data: T) -> Node<'a, T> {
Node {
successor: Box::new(self.successor.append_item(new_data)),
..*self
}
}
}
struct End;
impl<'a, T: 'a> Element<'a, T> for End {
fn append_item(self: Box<Self>, data: T) -> Node<'a, T> {
Node {
data,
successor: self,
}
}
}

Lifetime collision when bounding reference of a trait as IntoIterator

I tried to implement some graph algorithms on generic graphs. For that, I defined two graph traits which would return either a generic trait (having set-operations) SetGraph or an IntoIterator used to iterate over the nodes NeighborhoodIteratorGraph.
pub trait NeighborhoodIteratorGraph<'a> {
//which into_iterator do we have?
type IntoIter: 'a + std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter;
}
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&'a self, index: usize) -> &'a Self::S;
}
Because one is usually able to iterate over sets, I also implemented NeighborhoodIteratorGraph for all SetGraph which are able to iterate over their sets.
impl<'a, G> NeighborhoodIteratorGraph<'a> for G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter {
self.get_neighborhood(index)
}
}
I needed to add a lifetime to NeighborrhoodIteratorGraph otherwise the compiler would tell me my implementation would have an unbounded lifetime.
However I quicky run into problems with these lifetimes and I get an error for the following code:
struct Foo<'a, G: NeighborhoodIteratorGraph<'a>> {
graph: G,
//otherwise we get an error because 'a wouldn't be used
_marker: std::marker::PhantomData<&'a G>,
}
impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
It seems that the PhantomData field is more a hack and I can't find a way in which I get a set refernce which can be seen as a IntoIterator object.
Here is the Rust Playground of the problem.
Full error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
--> src/lib.rs:34:5
|
34 | / pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
35 | | where
36 | | I: std::iter::IntoIterator<Item = usize>,
| |_________________________________________________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:38:21
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 33:6...
--> src/lib.rs:33:6
|
33 | impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&'a G`
found `&G`
What you want is a workaround for the lack of generic associated types, which are currently very unstable. Something Like
pub trait NeighborhoodIteratorGraph {
type IntoIter<'a>: std::iter::IntoIterator<Item = usize> + 'a;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter<'b>;
}
would serve you perfectly if they were stable.
The first thing I did is remove the lifetime bound on NeighborhoodIteratorGraph and add it to the return type:
pub trait NeighborhoodIteratorGraph {
type IntoIter: std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b;
}
I then removed unnecessary lifetime annotations from SetGraph:
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&self, index: usize) -> &Self::S;
}
I then changed the blanket impl's signature to match the modified traits, and changed the impl from G to &'a G to properly constrain the lifetime 'a:
impl<'a, G> NeighborhoodIteratorGraph for &'a G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b,
{
self.get_neighborhood(index)
}
}
Because of those changes I was able to simplify Foo and its impl:
struct Foo<G: NeighborhoodIteratorGraph> {
graph: G,
}
impl<G: NeighborhoodIteratorGraph> Foo<G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
Leaving the compiler output with nothing but dead code warnings. Playground link

What happens when a Rust struct contains a lifetimed trait?

Ok, so I'm a total Rust newbie, and I'm experimenting with Rocket. That web framework passes a Form<MyStruct>, and I want to transfer that MyStruct into my own custom struct.
struct Consumer<T> {
d: T,
}
impl<T> Consumer<T> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner() }
}
}
That doesn't work of course, I get:
the trait `rocket::request::FromForm<'_>` is not implemented for `T`
Next attempt:
impl<T> Consumer<T> where T: FromForm {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
Uh oh:
impl<T> Consumer<T> where T: FromForm {
^^^^^^^^ expected lifetime parameter
So now I find myself completely unable to fix this! The best I can come up with is:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
But that results in this error:
51 | fn new(form: Form<T>) -> Self {
| _________^
52 | | Consumer { d: form.into_inner }
53 | | }
| |_________^ lifetime mismatch
= note: expected type `rocket::request::FromForm<'_>`
found type `rocket::request::FromForm<'f>`
Verifiable example: https://hastebin.com/eqihaqodux.makefile
Form also has a lifetime parameter. If you tie it to the lifetime of FromForm, then you'll move forward a little:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}
As a general rule, if you return an object that depends on data in another object, then you'll need to link their lifetimes together like this.
At this point, you'll see another error, which conveniently gives you all the information you need to fix it:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:50:17
|
48 | impl<'f, T> Consumer<T> where T: FromForm<'f> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
49 | fn new(form: Form<'f, T>) -> Self {
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/main.rs:50:17
|
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
The into_inner method on Form requires that it's type parameter T has the 'static lifetime, and the error message suggests adding this constraint.
With these changes, it will compile:
impl<'f, T: 'static> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}

Fn as trait concrete lifetime required

I want to use an API that I can modify reg:
struct Ctx;
trait Foo {}
trait Ex {
fn do_<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a>;
}
impl<F> Ex for F
where
F: for<'a> Fn(&'a mut Ctx) -> Box<Foo + 'a>,
{
fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
(*self)(ecx)
}
}
fn reg<F>(name: &str, ext: F)
where
F: Ex + 'static,
{
}
//My code starts here
struct Boo;
impl Boo {
fn f1<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a> {
unimplemented!();
}
}
fn main() {
let boo = Boo;
reg("aaa", move |cx| boo.f1(cx));
}
But I got an error:
error[E0271]: type mismatch resolving `for<'a> <[closure#src/main.rs:33:16: 33:36 boo:_] as std::ops::FnOnce<(&'a mut Ctx,)>>::Output == std::boxed::Box<Foo + 'a>`
--> src/main.rs:33:5
|
33 | reg("aaa", move |cx| boo.f1(cx));
| ^^^ expected bound lifetime parameter 'a, found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#9r
= note: required because of the requirements on the impl of `Ex` for `[closure#src/main.rs:33:16: 33:36 boo:_]`
= note: required by `reg`
error[E0281]: type mismatch: `[closure#src/main.rs:33:16: 33:36 boo:_]` implements the trait `std::ops::Fn<(&mut Ctx,)>`, but the trait `for<'a> std::ops::Fn<(&'a mut Ctx,)>` is required
--> src/main.rs:33:5
|
33 | reg("aaa", move |cx| boo.f1(cx));
| ^^^ -------------------- implements `std::ops::Fn<(&mut Ctx,)>`
| |
| requires `for<'a> std::ops::Fn<(&'a mut Ctx,)>`
| expected concrete lifetime, found bound lifetime parameter 'a
|
= note: required because of the requirements on the impl of `Ex` for `[closure#src/main.rs:33:16: 33:36 boo:_]`
= note: required by `reg`
How can I fix this?
In real code my struct Boo contains some data,
and want to call reg for it twice, so I not implement trait Ex, but
try to use closure.
Looks like issue #38714.
While it is being fixed, you can directly implement Ex for Boo.
impl Ex for Boo {
fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
self.f1(ecx)
}
}
fn main() {
let boo = Boo;
reg("aaa", boo);
}
In real code my struct Boo contains some data, and want to call reg for it twice, so I not implement trait Ex, but try to use closure.
You'll not be able to do that with the code you provided. move |cx| boo.f1(cx) moves boo into the closure, and you can't use boo after that.
If you want to share data, you'll need to use Rc in Boo.

Storing a closure with lifetimes in a struct

I'm trying to store closures in a Vec that is part of a struct. The closure is a factory function which receives 2 references as arguments and produces a trait object which stores the references the closure receives as arguments.
Because of that, the produced trait object has a lifetime that must not exceed the lifetime of the references. Also component_registrations will be accessed from multiple threads and is therefore wrapped in an Arc<Mutex>.
I tried implementing it but the compiler says that the generic parameter F of the register_component function doesn't satisfy the trait bound used in component_registrations.
This is the relevant part of the code:
use std::sync::Mutex;
use std::sync::Arc;
pub mod gl {
pub struct Gl();
}
pub struct ComponentRegistry<'a> {
gl: &'a gl::Gl
}
pub trait Component<'a> {
}
pub struct Application {
component_registrations: Arc<Mutex<Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b>> + Send + 'static>>>>
}
impl Application {
pub fn new() -> Application {
Application {
component_registrations: Arc::new(Mutex::new(vec![]))
}
}
pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
self.component_registrations.lock().unwrap().push(Box::new(register));
}
}
error[E0277]: the trait bound `for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not satisfied
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ the trait `for<'b> std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not implemented for `F`
|
= help: consider adding a `where for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` bound
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
error[E0271]: type mismatch resolving `for<'b> <F as std::ops::FnOnce<(&'b ComponentRegistry<'b>, &'b gl::Gl)>>::Output == std::boxed::Box<Component<'b>>`
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
|
note: concrete lifetime that was found is the lifetime 'a as defined on the method body at 26:5
--> src/main.rs:26:5
|
26 | / pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
27 | | self.component_registrations.lock().unwrap().push(Box::new(register));
28 | | }
| |_____^
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
If you use a higher ranked lifetime when you define your component_registrations struct field, you should use a higher ranked lifetime for F as well.
Also, if you say Box<Component<'b>>, it really means Box<Component<'b> + 'static> (so the trait object can contain only owned data). What you really need is Box<Component<'b> + 'b>, which means it is a trait object that implements Component<'b> and it can also contain borrowed data which live at least as long as 'b.
The relevant part is
pub struct Application {
component_registrations: Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static>>
}
impl Application {
pub fn register_component<F>(&mut self, register: F) where F: for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static {
self.component_registrations.push(Box::new(register));
}
}
You can see the full example. Note, that I removed the Arc and Mutex types from your example since they were not relevant.

Resources