Lifetime issue with mutable trait reference in struct

Blockquote

Hello guys, unfortunately, the rust lifetime/ borrow checker is driving me crazy for days now :frowning:

I'm getting this rust lifetime error, but I don't understand why it happens and especially how to fix/ work around it:

    error: lifetime may not live long enough
    --> src/console.rs:454:39
        |
    422 |     conn: &mut dyn ConnectionTrait<TlsStream<TcpStream>>,
        |     ----  - let's call the lifetime of this reference `'1`
        |     |
        |     has type `&mut dyn ConnectionTrait<'2, TlsStream<TcpStream>>`
    ...
    454 |       let logger = ConsoleLogger::new(conn);
        |                                       ^^^^ cast requires that `'1` must outlive `'2`

The (reduced) code looks like this:

    pub trait ConnectionTrait<'a, S>: Read + Write + BufRead + Send + Sync {
    }


    pub struct ConsoleLogger<'a> {
        conn: &'a mut dyn ConnectionTrait<'a, TlsStream<TcpStream>>,
    }

    impl<'a> ConsoleLogger<'a> {
        pub fn new(conn: &'a mut dyn ConnectionTrait<'a, TlsStream<TcpStream>>) -> Self {
            ConsoleLogger { conn }
        }
    }

    impl log::Log for ConsoleLogger<'_> {
        // ...
    }


    fn cmd_test(&self, conn: &mut dyn ConnectionTrait<TlsStream<TcpStream>>) {
        ...
        {
            let logger = ConsoleLogger::new(conn);
            ...
        }
        ...
    }

It makes sense, that the ConnectionTrait (or the things contained within it) must outlive the reference to it (referenced as "conn"). But why is the lifetime affected in any way by "ConsoleLogger::new(conn)"?

Any help, especially how to get this in general super simple piece of code to work, would be really appreciated. :pray: :pray: :pray:

This is never what you want. Since mutable borrows are invariant in the referent type, this means that the referent must be borrowed for the whole of its lifetime.

You should parameterize your ConsoleLogger by two distinct lifetime parameters and store e.g. &'a mut dyn ConnectionTrait<'b, _> in it.

1 Like

Another possibility might be going higher-ranked, but it's unclear what the point of the lifetime in the trait is so this may or may not work.

Another possibility is going more generic.

impl<'a, S, T: ?Sized + ConnectionTrait<'a, S>> ConnectionTrait<'a, S> for &mut T {
}

pub struct ConsoleLogger<T> {
    conn: T
}

impl<'a, T> ConsoleLogger<T>
where
    T: ConnectionTrait<'a, TlsStream<TcpStream>>

Thank you guys! @paramagnetic, I tried your solution and it works perfectly! @quinedot I'll also try your suggestions in the next few days. Thanks again! :+1: