Satisfying lifetimes for traits that are required by one another - rust

Im trying to write a basic nary tree, where I have several traits that are all intended to work on structs which will form the nodes of the tree. These structs will have mutable references to the other nodes of the tree, so I have included lifetime parameters in my trait definitions.
For instance, this is the trait which all the structs will implement:
pub trait Node<'a>: NodeClone {
fn value(&self) -> String;
fn parent(&self) -> Option<Box<dyn Node>>;
fn children(&self) -> Vec<Box<dyn Node>>;
fn set_parent(&mut self, parent: &mut Box<dyn Node>);
fn push_child(&mut self, child: &mut Box<dyn Node>);
fn to_string(&self, current: &mut String) -> String;
}
Anything which implements Node must also implement NodeClone, which looks like:
pub trait NodeClone {
fn clone_box(&self) -> Box<dyn Node>;
}
impl<'a, T> NodeClone for T where T: 'static + Node<'a> + Clone, {
fn clone_box(&self) -> Box<dyn Node> {
return Box::new(self.clone());
}
}
impl<'a> Clone for Box<dyn Node<'a>> {
fn clone(&self) -> Box<dyn Node<'a>> {
return self.clone_box();
}
}
This is one of the structs which will form the tree:
#[derive(Clone)]
pub struct Operation<'a> {
pub parent: Option<&'a mut Box<dyn Node<'a>>>,
pub children: Vec<&'a mut Box<dyn Node<'a>>>
}
When I then try and implement Node for Operation like:
impl<'a> Node<'a> for Operation<'a>
I get the error that:
error[E0477]: the type `Operation<'a>` does not fulfill the required lifetime
--> src/language/components/node/operation.rs:31:10
|
31 | impl<'a> Node<'a> for Operation<'a> {
| ^^^^^^^^
|
note: type must satisfy the static lifetime as required by this binding
--> src/language/components/node.rs:15:21
|
15 | pub trait Node<'a>: NodeClone {
|
When I change the implementation of Operation to include a static lifetime:
impl<'a> Node<'a> for Operation<'static>
The fields of my struct Operation give me the error that:
the trait bound `&mut Box<(dyn Node<'_> + 'static)>: Clone` is not satisfied
Im not sure which lifetime I should change and where to solve this. Please help!

Related

Lifetime and associated types

I have this enum:
enum Node<T> {
Leaf(T),
Children(Vec<Node<T>>),
}
And want to implement the Iterator trait for Node.
I created this struct and tried to implement the IntoIterator trait:
struct NodeIter<'a, T>{
children: &'a [Node<T>],
parent: Option<&'a Node<T>>,
}
impl<'a, T> IntoIterator for Node<T> {
type Item = T;
type IntoIter = NodeIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
I can not figure out the correct lifetime specifiers, I end up getting this error:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/tree_my.rs:44:6
|
44 | impl<'a, T> IntoIterator for Node<T> {
| ^^ unconstrained lifetime parameter
I am new to Rust and I am not sure if I am doing it wrong or if it is not possible. Because I have read about similar problems. The problem seems to have something to do with traits (IntoIterator in my case) and associated types. I also read something about GAT.
Maybe someone could explains this problem and how one would solve it.
Rust Playground
IntoIterator::into_iter consumes its argument. This means that once you've called node.into_iter() the node no longer exists, but it looks like you want your NodeIter to keep references to node which is impossible since it's no longer around.
You will need to either change NodeIter to take ownership of the original Node so that NodeIter can keep the Node alive for as long as it needs it, or implement IntoIter for references to Node (which will consume the reference, but keep the original Node intact):
enum Node<T> {
Leaf(T),
Children(Vec<Node<T>>),
}
struct NodeIter<'a, T>{
children: &'a [Node<T>],
parent: Option<&'a Node<T>>,
}
impl<'a, T> Iterator for NodeIter<'a, T> {
type Item = T;
fn next (&mut self) -> Option<Self::Item> {
todo!();
}
}
impl<'a, T> IntoIterator for &'a Node<T> {
type Item = T;
type IntoIter = NodeIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
Playground

Trait for conversion of references and owned values to Cow

I have a function that can handle both owned and borrowed values of some type Foo by accepting a Cow<'_, Foo>. However, I'd like to make it more convenient by allowing to pass in owned or borrowed Foos directly.
Is it possible to have a conversion trait to Cow that's implemented both on a reference type and its owned version?
This is what I tried:
trait Convert<'a> : Clone {
fn into_cow(self) -> Cow<'a, Self>;
}
// Works
impl<'a> Convert<'a> for Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("owned");
Cow::Owned(self)
}
}
// Doesn't work
impl<'a> Convert<'a> for &'a Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("borrowed");
Cow::Borrowed(self)
}
}
The borrowed version says that Borrowed expected a &&'a Foo but found a &'a Foo.
Self in the implementation of a trait for &Foo is &Foo, so into_cow() doesn't return the same type in both impls.
One solution would be to change the return type to Cow<'a, Foo>, but that of course limits the trait to only work on Foo.
A better way is to make the owned type a generic parameter of Convert like this:
trait Convert<'a, T: Clone> {
fn into_cow(self) -> Cow<'a, T>;
}
impl<'a, T: Clone> Convert<'a, T> for T {
fn into_cow(self) -> Cow<'a, T> {
println!("owned");
Cow::Owned(self)
}
}
impl<'a, T: Clone> Convert<'a, T> for &'a T {
fn into_cow(self) -> Cow<'a, T> {
println!("borrowed");
Cow::Borrowed(self)
}
}
fn take_foo<'a>(foo: impl Convert<'a, Foo>) {
let cow = foo.into_cow();
}
fn main() {
take_foo(&Foo{});
take_foo(Foo{});
}
Do you ever make use of the ownership, or always reborrow it? If only reborrowing, is std::convert::AsRef what you're looking for?
fn take_foo(foo: impl AsRef<Foo>) {
let foo: &Foo = foo.as_ref();
todo!();
}

How may I return an iterator over the keys of a HashMap that clones the keys?

I am defining a trait called ShyAssociation that returns a lazy iterator of the keys of an associative structure. The iterator should either borrow the keys as immutable or clone them. The keys are always &'static str. All I need is an iterator that returns &'static str.
Here is the trait with my attempt at the method for the keys iterator:
use std::collections::{hash_map::Keys, HashMap};
#[derive(Clone, PartialEq, Debug)]
pub enum ShyValue {
Boolean(bool),
Integer(i64),
Rational(f64),
String(String),
Error(String),
}
pub trait ShyAssociation {
fn keys(&self) -> Keys<&'static str, ShyValue>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys(&self) -> Keys<&'static str, ShyValue> {
self.keys().cloned()
}
}
It won't compile.
error[E0308]: mismatched types
--> src/lib.rs:18:9
|
18 | self.keys().cloned()
| ^^^^^^^^^^^^^^^^^^^^ expected struct `std::collections::hash_map::Keys`, found struct `std::iter::Cloned`
|
= note: expected type `std::collections::hash_map::Keys<'_, &'static str, _>`
found type `std::iter::Cloned<std::collections::hash_map::Keys<'_, &str, _>>`
UPDATE:
I am attempting a variation on Alexander Huszagh's answer, but have a syntax error:
use std::collections::{hash_map::Keys, HashMap};
#[derive(Clone, PartialEq, Debug)]
pub enum ShyValue {
Boolean(bool),
Integer(i64),
Rational(f64),
String(String),
Error(String),
}
pub trait ShyAssociation<'a> {
fn keys(&self) -> Box<Iterator<Item=&'static str> + 'a>;
}
impl<'a> ShyAssociation<'a> for HashMap<&'static str, ShyValue> {
fn keys(&self) -> Box<Iterator<Item=&'static str> + 'a> {
Box::new<(Iterator<Item=&'static str> + 'a)>(self.keys().cloned())
}
}
The error message is on the "str" in the Iterator Item definition for keys:
expected `:`, found `str`
expected `:`rustc
shy_association.rs(59, 42): expected `:`
The issue is that you're manually specifying a type that doesn't match the return type. iter::Cloned<Keys<_, _>> is not the same as Keys<_, _>. A simple fix is to change your return type to iter::Cloned<Keys<&'static str, ShyValue>>.
pub trait ShyAssociation {
fn keys(&self) -> iter::Cloned<Keys<&'static str, ShyValue>>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys(&self) -> iter::Cloned<Keys<&'static str, ShyValue>> {
self.keys().cloned()
}
}
If would like to return a type that implements a trait (which will not work in the above example, since this is only valid for non-trait functions and methods), you may also do:
pub fn keys<'a>(hash_map: &'a HashMap<&'static str, ShyValue>) -> impl Iterator<Item = &'a str> {
hash_map.keys().cloned()
}
If you would like to use Box<dyn Iterator> so you may use it in a trait method, you may do:
pub trait ShyAssociation {
fn keys<'a>(&'a self) -> Box<(dyn Iterator<Item = &'static str> + 'a)>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys<'a>(&'a self) -> Box<(dyn Iterator<Item = &'static str> + 'a)> {
Box::new(self.keys().cloned())
}
}
The 'a lifetime is necessary in order to limit the lifetime of the iterator to that of the HashMap.

How do I return the result of get_mut from a HashMap or a HashSet?

I'm trying to wrap a HashMap, as defined below, to return a mutable reference from a HashMap:
use std::{collections::HashMap, marker::PhantomData};
struct Id<T>(usize, PhantomData<T>);
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
type Output = &'a mut T;
fn index(&mut self, id: &'a Id<T>) -> Self::Output {
self.0.get_mut(id).unwrap()
}
}
And the resulting error:
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/id_container.rs:54:5
|
54 | / fn index(&mut self, id: &'a Id<T>) -> Self::Output {
55 | | self.0.get_mut(id).unwrap()
56 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/id_container.rs:55:9
|
55 | self.0.get_mut(id).unwrap()
| ^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 52:6...
--> src/id_container.rs:52:6
|
52 | impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
| ^^
= note: ...so that the types are compatible:
expected std::ops::Index<id_container::Id<T>>
found std::ops::Index<id_container::Id<T>>
Why can't the compiler extend the lifetime of the get_mut? The IdCollection would then be borrowed mutably.
Note that I tried using a std::collections::HashSet<IdWrapper<T>> instead of a HashMap:
struct IdWrapper<T> {
id: Id<T>,
t: T,
}
Implementing the proper borrow etc. so I can use the Id<T> as a key.
However, HashSet doesn't offer a mutable getter (which makes sense since you don't want to mutate what's used for your hash). However in my case only part of the object should be immutable. Casting a const type to a non-const is UB so this is out of the question.
Can I achieve what I want? Do I have to use some wrapper such as a Box? Although I'd rather avoid any indirection...
EDIT
Ok I'm an idiot. First I missed the IndexMut instead of the Index, and I forgot the & when specifying the Self::Output in the signature.
Here's my full code below:
pub struct Id<T>(usize, PhantomData<T>);
impl<T> std::fmt::Display for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, o: &Self) -> bool {
self.0 == o.0
}
}
impl<T> Eq for Id<T> {}
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> IntoIterator for &'a IdCollection<T> {
type Item = (&'a Id<T>, &'a T);
type IntoIter = std::collections::hash_map::Iter<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut IdCollection<T> {
type Item = (&'a Id<T>, &'a mut T);
type IntoIter = std::collections::hash_map::IterMut<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> std::ops::Index<Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output {
self.0.get(&id).unwrap()
}
}
impl<T> std::ops::IndexMut<Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output {
self.0.get_mut(&id).unwrap()
}
}
impl<T> std::ops::Index<&Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: &Id<T>) -> &Self::Output {
self.0.get(id).unwrap()
}
}
impl<T> std::ops::IndexMut<&Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: &Id<T>) -> &mut Self::Output {
self.0.get_mut(id).unwrap()
}
}
If I understand correctly what you try to achieve, then I have to tell you, that it is a bit more complex than you originally thought it would be.
First of all, you have to realise, that if you like to use a HashMap then the type of the key required to be hashable and comparable. Therefore the generic type parameter T in Id<T> has to be bound to those traits in order to make Id hashable and comparable.
The second thing you need to understand is that there are two different traits to deal with the indexing operator: Index for immutable data access, and IndexMut for mutable one.
use std::{
marker::PhantomData,
collections::HashMap,
cmp::{
Eq,
PartialEq,
},
ops::{
Index,
IndexMut,
},
hash::Hash,
};
#[derive(PartialEq, Hash)]
struct Id<T>(usize, PhantomData<T>)
where T: PartialEq + Hash;
impl<T> Eq for Id<T>
where T: PartialEq + Hash
{}
struct IdCollection<T>(HashMap<Id<T>, T>)
where T: PartialEq + Hash;
impl<T> Index<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output
{
self.0.get(&id).unwrap()
}
}
impl<T> IndexMut<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output
{
self.0.get_mut(&id).unwrap()
}
}
fn main()
{
let mut i = IdCollection(HashMap::new());
i.0.insert(Id(12, PhantomData), 99i32);
println!("{:?}", i[Id(12, PhantomData)]);
i[Id(12, PhantomData)] = 54i32;
println!("{:?}", i[Id(12, PhantomData)]);
}
It may seem a bit surprising, but IndexMut is not designed to insert an element into the collection but to actually modify an existing one. That's the main reason why HashMap does not implement IndexMut -- and that's also the reason why the above example uses the HashMap::insert method to initially place the data. As you can see, later on, when the value is already available we can modify it via the IdCollection::index_mut.

Trait to store structs with different generic parameters

I need to store in the same Vec instances of the same struct, but with different generic parameters. This is the struct definition:
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
The struct has a method returning an iterator to a type that does not depend on the generic type parameter T:
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<&i32> {
unimplemented!()
}
}
I need to access this method for those different structs in the vector, so I've implemented this trait:
type Iter<'a> = Iterator<Item=&'a i32>;
trait Trait {
fn iter(&self) -> Box<Iter>;
}
And I've implemented the trait for Struct:
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> Box<Iter> {
Box::new(self.iter())
}
}
But the compiler complains:
<anon>:21:9: 21:30 error: type mismatch resolving `<core::slice::Iter<'_, &i32> as core::iter::Iterator>::Item == &i32`:
expected &-ptr,
found i32 [E0271]
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
<anon>:21:9: 21:30 help: see the detailed explanation for E0271
<anon>:21:9: 21:30 note: required for the cast to the object type `core::iter::Iterator<Item=&i32> + 'static`
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
I've tried different possibilities for lifetime parameters in the trait, but none of them work. How can I make this work?
Rust Playground snippet
Edit
As pointed out by #MatthieuM. one problem is that the type alias is not working properly. Here's another example demonstrating this:
use std::slice;
type Iter<'a> = Iterator<Item=&'a i32>;
struct Struct<'a> { _phantom: std::marker::PhantomData<&'a i32> }
impl<'a> Struct<'a> {
fn direct<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iterator<Item=&'a i32>
{ i }
fn aliased<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iter<'a>
{ i }
}
In this example, direct compiles, but aliased not, with the error:
<anon>:12:7: 12:8 error: the type `core::slice::Iter<'a, i32>` does not fulfill the required lifetime
<anon>:12 { i }
^
note: type must outlive the static lifetime
But they seem to be the same thing. What's happening?
Problem 1 — slice::Iter<T> has an Iterator::Item of &T, thus your reference levels are mismatched. Change your method to be
fn iter(&self) -> slice::Iter<i32>
Problem 2 — Box<SomeTrait> is equivalent to Box<SomeTrait + 'static>, but your iterator does not live for the 'static lifetime. You need to explicitly bring in a lifetime:
Box<SomeTrait + 'a>
Problem 3 — I don't understand how you can create a type alias for a trait, that seems very odd. You probably don't want it anyway. Instead, create a type alias for the whole boxed version:
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
Problem 4 — Rearrange your main so that references will live long enough and add mutability:
fn main() {
let i = 3;
let v = vec![&i];
let mut traits : Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct{ items: v }));
}
All together:
use std::slice;
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
trait Trait {
fn iter<'a>(&'a self) -> IterBox;
}
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<i32> {
unimplemented!()
}
}
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> IterBox {
Box::new(self.iter())
}
}
fn main() {
let i = 3;
let v = vec![&i];
let mut traits: Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct { items: v }));
}

Resources