Vladislav
Vladislav

Reputation: 33

Find index of a dyn trait in Vector

I need to find the index of an element, given by reference, in a vector that hold references to elements that satisfy a trait.

There is a layer system, which includes the layer trait and a layer stack (to have control over operations):

pub trait Layer {
  fn new(name: &str) -> Self where Self: Sized;

  fn on_attach(&mut self);
  fn on_detach(&mut self);
  fn on_update(&mut self);
  fn on_event(&mut self, event: &mut dyn Event);

  fn get_debug_name(&self) -> &String;
}

impl PartialEq for dyn Layer {
  fn eq(&self, other: &dyn Layer) -> bool {
    self.get_debug_name() == other.get_debug_name()
  }
}

pub struct LayerStack<'a> {
  layers: Vec<&'a mut dyn Layer>,
  overlay_position: usize,
}

impl<'a> LayerStack<'a> {
  pub fn new() -> Self {
    Self {
      layers: Vec::new(),
      overlay_position: 0
    }
  }

  // ...

  pub fn find_index(&self, element: &'a dyn Layer) -> Option<usize> {
    self.layers.iter().position(|item| *item == element)
  }
}

There is an error in the find_index method:

error: lifetime may not live long enough
8  | impl<'a> LayerStack<'a> {
   |      -- lifetime `'a` defined here
...
48 |     self.layers.iter().position(|item| *item == element)
   |                                        ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`

This is some kind of a lifetime issue but I can't see any problems here. What can I do about it?

I know that owning the elements themselves instead of references partly solves this problem, but I have to only have mutable ref to layers but not own them. Static lifetime in a struct generic also doesn't work: the layers don't have a static lifetime.

I'm a complete newbie at rust, so dealing with all the lifetime things is a complete nightmare

Upvotes: 2

Views: 186

Answers (1)

&#214;mer Erden
&#214;mer Erden

Reputation: 8813

In the implementation below; type expression(dyn Layer) is called as trait object. (need to note that Layer needs to be an object safe trait)

impl PartialEq for dyn Layer { /*...*/ }

Since dyn Layer is not used as a type argument of a generic type, Rust follows the rules below (reference:

  • If the trait is defined with a single lifetime bound then that bound is used.
  • If 'static is used for any lifetime bound then 'static is used.
  • If the trait has no lifetime bounds, then the lifetime is inferred in expressions and is 'static outside of expressions.

The highlighted part is applied to your implementation since there is no bound defined in the implementation you made.

Thus we can tell that your PartialEq implementation is only valid when the operands have static lifetime for == operator. But your operands live in 'a which can be 'static or something else.

impl<'a> LayerStack<'a> {
    //...
    pub fn find_index(&self, element: &'a dyn Layer) -> Option<usize> {
        self.layers.iter().position(|item| *item == element)
    }

To fix this problem we can apply the first rule (adding single lifetime bound)

impl<'a> PartialEq for dyn Layer + 'a { /*...*/ }

Playground


Or even better, from the reference above:

If '_ is used as the lifetime bound then the bound follows the usual elision rules.

It can be implemented like this:

impl PartialEq for dyn Layer + '_ { /*...*/ }

Upvotes: 2

Related Questions