Let's say I have this type:
pub struct Id(std::path::PathBuf);
It looks reasonable to construct it from:
- any type that implements
AsRef<std::path::Path>
. In this case we will have to copy the type. - an owned type:
std::path::PathBuf
. Here we just need to move it (no need to clone).
Initially I wanted to use Cow<>
, because it looks like exactly what I need, it implements all the logic: if it is a borrow -> clone, otherwise -> move:
pub fn into_owned(self) -> <B as ToOwned>::Owned {
match self {
Borrowed(borrowed) => borrowed.to_owned(),
Owned(owned) => owned,
}
}
But then I quickly realised it is not a trait, and I cannot write this:
impl From<Cow<...>> for Id
My next attempt was to this:
impl From<&std::path::Path> for Id {
fn from(value: &std::path::Path) -> Self {
Id(value.to_path_buf())
}
}
impl From<std::path::PathBuf> for Id {
fn from(value: std::path::PathBuf) -> Self {
Id(value)
}
}
But there are two issues:
- copy-paste. I just need Cow-like thing that can decide for me what it holds (reference or value) and then it should be able to give me owned version in the most efficient way. The fact that I do not have this, made me write two implementations of
From
. - I am not sure, but I am not using
AsRef<std::path::Path>
, which means that it will not be able to take any type that implementsAsRef<std::path::Path>
.
This version did not work either:
impl<T: AsRef<std::path::Path>> From<T> for Id {
fn from(value: T) -> Self {
Id(value.as_ref().to_path_buf())
}
}
impl From<std::path::PathBuf> for Id {
fn from(value: std::path::PathBuf) -> Self {
Id(value)
}
}
error[E0119]: conflicting implementations of trait `From<PathBuf>` for type `Id`
--> prod/quotalib/src/id.rs:48:1
|
43 | impl<T: AsRef<std::path::Path>> From<T> for Id {
| ---------------------------------------------- first implementation here
...
48 | impl From<std::path::PathBuf> for Id {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Id`
which of course makes sense...
So, how would you write efficient (== no unnecessary clones) From
trait without copy-paste?
To sum up:
I am trying to find a way to implement a (1) single From<>
trait (== no copy-paste), that allows me to (2) create Id
from:
- any type that implements
AsRef<std::path::Path>
- or an owned type:
std::path::PathBuf
(3) without cloning where it is not necessary (== if from()
was called with PathBuf
, there is no need to clone it).
Is there a way to satisfy all 3 points?