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:

Secondly, we need to know the type of the conversion result. Akin to
ToOwned::Owned
, this should be an associated type, such that we don't need to know the owning type.
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() }
}