The code below illustrates Error behaviour which, I think, is reasonably desirable but I don't know how to achieve it. Does anyone know of any solutions?
#[derive(Debug)]
pub struct MyError {
pub code: u16,
pub reason: String,
}
impl<E> From<E> for MyError
where
E: std::fmt::Display,
{
fn from(value: E) -> Self {
Self {
code: 400,
reason: value.to_string(),
}
}
}
impl std::error::Error for MyError {}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}] {}", self.code, self.reason)
}
}
// error[E0119]: conflicting implementations of trait `std::convert::From<MyError>` for type `MyError`
// --> src/main.rs:7:1
// |
// 7 | impl<E> From<E> for MyError
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// |
// = note: conflicting implementation in crate `core`:
// - impl<T> std::convert::From<T> for T;
fn main() {
let err: MyError = "testing".into();
let any_err: Box<dyn std::error::Error> = Box::new(err);
assert_eq!(any_err.to_string(), "[400] testing".to_string());
}
T implements From<T> and Into<T>. But your blanket implementation also tries to implement From<MyError> for MyError, since MyError implements Display.
Specialization could help but there's currently no roadmap to stabilize specialization as far as I know.
I don't see how negative bounds could help, and they may not be what you think they are (it means a type has explicitly opted out of ever[1] implementing a trait, not that it merely hasn't implemented a trait).
MyError is Display, so your From impl applies to MyError itself (since it meets the Display bound). That conflicts with the standard library's transitive From<T> for T impl.