Perhaps look at
Path/PathBuf as the other commonly used pair of borrowed/owned types. They implement things symmetrically.
Also, I don’t know how big of a deal this is given the owned types usually deref to the borrowed type. In some sense, just implementing things for the borrowed variants can reduce amount of boilerplate. Then let deref coercion kick in. It may make certain generic bounds not work as-is, but can be worked around via other means (e.g. instead of
str: PartialOrd<T> type of thing you’d use
T: AsRef<str> or
T: Borrow<str>, as appropriate). Or just implement all the PartialXYZ upfront .
Another consideration, particularly for functions, is to consider taking the borrowed type directly rather than via a generic bound. So instead of
fn foo<T: PartialOrd<str>>(t: &T) you use
fn foo(t: &str). This can prevent code bloat if lots of different T types were substituted - each one would get a specialized version of foo (ie monomorphization). Instead, you make caller cough up a
&str via whatever means and pass that directly.