I was playing around with extending std::borrow::Cow
and discovered that currently, std implements From<> for Cow<'a, T>
for each potential type separately.
For example, std::string module explicitly implements a bunch of From traits for Cow<'a, str>
:
impl<'a> From<&'a str> for Cow<'a, str> ...
impl<'a> From<String> for Cow<'a, str> ...
impl<'a> From<&'a String> for Cow<'a, str> ...
On the surface, it would be quite useful to instead have three very simple blanket impls instead:
impl<'a, T> From<&'a T> for Cow<'a, T>
where T: ToOwned + ?Sized
{
fn from(s: &'a T) -> Cow<'a, T> { Cow::Borrowed(s) }
}
impl<'a, T> From<<T as ToOwned>::Owned> for Cow<'a, T>
where T: ToOwned + ?Sized
{
fn from(s: <T as ToOwned>::Owned) -> Cow<'a, T> { Cow::Owned(s) }
}
impl<'a, T> From<&'a <T as ToOwned>::Owned> for Cow<'a, T>
where T: ToOwned + ?Sized
{
fn from(s: &'a <T as ToOwned>::Owned) -> Cow<'a, T> { Cow::Borrowed(s.borrow()) }
}
However, if you actually do this, rustc will rightfully complain that (a) first and third impls conflict over From<&_> for Cow<'_, _>
, and (b) second impl conflicts with impl<T> From<T> for T
.
It seems a quite unfortunate limitation.
First, it leads to proliferation of completely identical boilerplate code across std and other crates.
Second, it means that I can never (ergonomically) use Cow
with third-party types/crates, unless the crate's author explicitly considers Cow and provides the necessary impls (because otherwise you run afoul of the orphan rules).
Is there any possible path forward for this problem? Is it expected that Rust will ever make it possible to write such overlapping impls (and get rid of all the boilerplate), or is this a fundamental limitation of Rust?