Parameter type must be valid for an anonymous lifetime

Hi all,
I am unable to understand a problem that I have encountered in a library that I am writing and am hoping that someone will be able to help me.

Below I have produced what I think is a minimal example that reproduces the problem. My library provides two traits, Plugin and PluginError. These traits should be implemented for custom types that are provided by authors who are writing plugin implementations in separate libraries. To make it easier for plugin authors, I want to provide default implementations of a few methods. In the example below, I provide a default implementation of the method named attribute_name.

Minimal example

The example may be found both below and at the playground here: Rust Playground

use std::{
    cell::{Ref, RefCell},
    error::Error,
    ffi::CString,
    rc::Rc,
};

type Attributes<T, E> = Rc<RefCell<Vec<Attribute<T, E>>>>;

struct Attribute<T, E> {
    name: CString,
    callback: fn() -> Result<T, E>,
}

trait PluginError: Error {
    fn new() -> Self;
}

trait Plugin<E: PluginError>
where
    Self: Sized,
{
    fn attributes(&self) -> Attributes<Self, E>;

    fn attribute_name(&self, id: usize) -> Result<Ref<CString>, E> {
        let attributes = self.attributes().borrow();
        // I'm not sure how to do the bounds check here so I index twice
        // into the attributes Vec. I don't think that this is pertinent.
        match attributes.get(id) {
            Some(_) => Ok(Ref::map(attributes, |a| &a[id].name)),
            None => Err(E::new()),
        }
    }
}

Error returned by the compiler

The following error message is repeated ~8 times before compilation outright fails.

error[E0311]: the parameter type `E` may not live long enough
  --> src/main.rs:26:26
   |
26 |         let attributes = self.attributes().borrow();
   |                          ^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound for `E`
note: the parameter type `E` must be valid for the anonymous lifetime #1 defined on the method body at 25:5...
  --> src/main.rs:25:5
   |
25 | /     fn attribute_name(&self, id: usize) -> Result<Ref<CString>, E> {
26 | |         let attributes = self.attributes().borrow();
27 | |         // I'm not sure how to do the bounds check here so I index twice into
28 | |         // the attributes Vec. I don't think that this is pertinent.
...  |
32 | |         }
33 | |     }
   | |_____^
note: ...so that the type `std::rc::Rc<std::cell::RefCell<std::vec::Vec<Attribute<Self, E>>>>` is not borrowed for too long
  --> src/main.rs:26:26
   |
26 |         let attributes = self.attributes().borrow();
   |                          ^^^^^^^^^^^^^^^^^

Could anyone provide an explanation of what I am doing wrong and how I might fix the problem? I suspect that there is a lifetime that is associated with the Ref that is returned by the attribute_name function and this is somehow conflicting another lifetime, but I have made little progress in even understanding what the issue is.

Thanks a lot!

Basically here's what might go wrong:

  1. PluginError might contain some reference.
  2. The Rc returned by the attributes field might be the last, so when the function ends, the reference count might reach zero, dropping the RefCell.

You fix this by, 1. adding 'static to the PluginError:

trait PluginError: Error + 'static {
    fn new() -> Self;
}

And you can return a &Attributes instead, which guarantees that the reference count is kept alive as long as &self is borrowed.

fn attributes(&self) -> &Attributes<Self, E>;

This should compile. playground

Thanks a lot @alice ! It worked like a charm, and I very much appreciate your explanation.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.