rustxml-builderanyhow

How to make a method returning XMLError compatible with anyhow::Error?


This is my code (XMLElement from xml-builder):

use anyhow::Result;
use xml_builder::XMLElement;
fn foo() -> Result<()> {
  let mut v = XMLElement::new("v");
  v.add_child(XMLElement::new("e"))?;
  Ok(())
}

It doesn't compile:

error[E0277]: the trait bound `XMLError: StdError` is not satisfied
  --> src/xml.rs:78:41
   |
78 |                 v.add_child(XMLElement::new("e"))?;
   |                                                  ^ the trait `StdError` is not implemented for `XMLError`
   |
   = help: the following other types implement trait `FromResidual<R>`:
             <Result<T, F> as FromResidual<Result<Infallible, E>>>
             <Result<T, F> as FromResidual<Yeet<E>>>
   = note: required for `anyhow::Error` to implement `From<XMLError>`
   = note: required for `Result<std::string::String, anyhow::Error>` to implement `FromResidual<Result<Infallible, XMLError>>`

How to I map XMLError to anyhow::Error? I tried .map_err(|e| anyhow::Error::new(e)), but it doesn't work either.


Solution

  • From the anyhow docs:

    Anyhow works with any error type that has an impl of std::error::Error, including ones defined in your crate.

    Unfortunately, XMLError does not implement that trait and, because of the orphan rule, you can't do anything about that.

    So, anyhow won't work out of the box. The anyhow::Error::new approach doesn't work either, for the same reason.

    Some possible ways around this:

    1. Use the newtype pattern. Create a new struct MyXMLError(XMLError) and then implement the StdError trait for that. Also implement From<XMLError> for your new type so that things work more ergonomically.
    2. Define a bunch of new error types (maybe via thiserror) that are more geared towards the user of your code rather than the underlying libraries like the xml-builder stuff. Have those error types implement the StdError type and create them as needed based on what sort of XLMError you find.