Smart pointer which owns its target

It's for this reason that I posit that IntoOwned wants Borrow and not Deref as a supertrait. Borrow is the existing trait that allows taking both references and T by value, so if IntoOwned wants to allow by-value, it seems incorrect to require a pointer-like type.

So what exactly breaks if you instead define IntoOwned as

pub trait IntoOwned<T>: Sized + Borrow<T> {
    type Owned: Borrow<T>;
    /* … */

?

I suspect it's this:

because if T is an owning type, then &U has two options: it could be a borrow of owning U, or it could be owning &U. Cow<U> could convert to U::Owned or Cow<U>. An explicit 'static bound on Owned isn't really helpful either, as the issue still exists for static references.

What I think is missing is in fact a definition of “owned.” I think it's “does not have a lifetime parameter,” but there's no way to provide a blanket implementation for owned types under this definition without also including unowned types.

What the Owned wrapper is thus doing is saying that yes, T is an owned type for the purpose of IntoOwned. (But unintuitively, Owned isn't, unless of course it is itself contained in another Owned.)

For this reason, Owned feels significantly more like a workaround than an actual productive type. But the thing is, even with Owned, &&T's “owned” type is &T, which doesn't meet our definition of “owned,” and at that, implements IntoOwned::Owned = T.

Perhaps it should be an invariant that typeof(x.into_owned()) == typeof(x.into_owned().into_owned()). Using Self::Owned = Owned<T> does seem reasonable for &T.... Alternatively, perhaps this wants for fully general specialization that allows specializing on associated types. That would give us a default implementation on T of returning itself and on &T of returning (*self).clone().into _owned(), as well as further specialized for Cow.

The compiler absolutely can't do this yet, but it'd look something like

pub trait IntoOwned: Sized {
    type Owned: Owned;
    fn into_owned(self) -> Self::Owned;
}

pub trait Owned = IntoOwned<Owned=Self>;

impl<T> IntoOwned for T {
    default {
        type Owned = Self;
        fn into_owned(self) -> Self { self }
    }
}

impl<T> IntoOwned for &'_ T
where T: Clone + IntoOwned,
{
    type Owned = T::Owned;
    fn into_owned(self) -> Self::Owned { (*self).clone().into_owned() }
}

impl<T> IntoOwned for Cow<'_, T>
where
    T: ToOwned,
    T::Owned: IntoOwned,
{
    type Owned = T::Owned::Owned;
    fn into_owned(self) -> Self::Owned { self.into_owned().into_owned() }
}
1 Like