This is an attempt at getting the best of both world, I might be looking at this the wrong way.
Whenever a function needs both a ref and and owned value of T, i'd like to declare the parameter as t: impl AsMagic<T> so that I may use t.as_ref() and t.to_owned(), however without creating unneeded copies when an owned value is available, and avoids unsafe.
When the function is passed a &T
and needs a &T, return self
and needs a T, return self.to_owned()
When the function is passed a T
and needs a &T, return &self
and need a T, return self
The following works but isnt free because is uses an enum and isnt ergonomic because .into() needs to be called when passing parameters.
Note that this is simply not possible if you really meant what is described as-is. If you pass something by value to a function, you can't return a reference to it, that'd be a dangling reference or a use-after-free.
Note that the counterpart of to_owned is borrow and notas_ref. Getting the reference from a Cow, for example, can be achieved through dereference or borrow. While Cow also lets you obtain a reference using as_ref, this is (arguably) semantically wrong, see Semantics of AsRef. Also see this note in the AsRef documentation:
[…] many smart pointers provide an as_ref implementation which simply returns a reference to the pointed-to value (but do not perform a cheap reference-to-reference conversion for that value). However, AsRef::as_ref should not be used for the sole purpose of dereferencing; instead ‘Deref coercion’ can be used:
let x = Box::new(5i32);
// Avoid this:
// let y: &i32 = x.as_ref();
// Better just write:
let y: &i32 = &x;
Moreover, ToOwned::to_owned does not consume the receiver, so it cannot achieve the goal of:
(At least not without an unnecessary clone.)
There is a method into_owned, which consumes self, but that's an inherent method of Cow and not part of any trait.
So what you are looking for is neither AsRef nor ToOwned. Instead you'd need a trait which combines Borrow with something like Cow::into_owned, which, opposed to to_owned, consumes self.
This is exactly what GenericCow (as mentioned above) does (with the addition of demanding a Deref implementation, see rationale).
See also PR #28811 which introduced that for several smart pointers. ↩︎