#Owned to reference conversion for enum containing multiple possible trait objects

12 messages · Page 1 of 1 (latest)

fossil meadow
#

Hi! Let's assume I have two traits Sink and Source and want to have an enum representing the owned variants of their trait objects Box<dyn T> and one that represents references to them &dyn T. Currently I have this:

#[derive(Clone, Copy)]
pub enum SinkOrSourceRef<'a> {
    Sink(&'a dyn Sink),
    Source(&'a dyn Source),
}

pub enum SinkOrSource {
    Sink(Box<dyn Sink>),
    Source(Box<dyn Source>),
}

How would I implement AsRef, Deref or any such trait so that I can create references of type SinkOrSourceRef for SinkOrSource? AsRef and Deref need the conversion methods to return references, but I have this sort of smart pointer. I tried this:

impl<'a> AsRef<SinkOrSourceRef<'a>> for SinkOrSource {
    fn as_ref(&self) -> &SinkOrSourceRef<'a> {
        match self {
            SinkOrSource::Sink(o) => &SinkOrSourceRef::Sink(o.as_ref()),
            SinkOrSource::Source(o) => &SinkOrSourceRef::Source(o.as_ref()),
        }
    }
}

However this does not work since: error[E0515]: cannot return value referencing temporary value

Any hint on how to set this up correctly?

tawdry fable
#

Your problem is effectively that AsRef wants the reference to be outside the type it returns (it hardcodes &T as a return type), but yours would be inside it

fossil meadow
#

Is there any other standard trait that is appropriate here?

#

Or do I really just have to write my own freestanding conversion method?

tawdry fable
#

Not really, no. All the traits for to-reference conversions want the reference on the outside.

fossil meadow
#

Wait, I could use From, or not?

tawdry fable
#

You could, but it would generally be considered confusing

#

.into() actually just borrowing is not what people expect of it

fossil meadow
#

Is there a way to solve this with unsafe? Like is there a safe way to just transmute? I can't really think of anything that would make sense but I'm kinda surprised this isn't something that's possible somehow 🤔

#

I guess the main issue here is really the enum being in the way and no one concrete inner type I could implement asref to instead ...

#

There's a bit of inner functionality, a sort of common inner trait, that both types share, I'll just use that as the asref target, since that's ultimately what I mostly will need this for anyway.