anyhow::Error does not impl std::error::Error

I have the function split_parse that splits and parses a given string by a given separator using FromStr.
Also, I've implemented FromStr for my own type and it has Err = anyhow::Error
And I can't use this type with split_parse because

trait std::error::Error is not implemented for anyhow::Error

What can I do with this?
I've tried changing Err constraint from std::error::Error to Into<anyhow::Error>, but that did not work.
Also, I can create its own ErrorType for my FromStr, but I don't want to do this.

use anyhow::{Context, Result};
use std::{str::FromStr};

pub fn split_parse<T: FromStr>(data: &str, sep: &str) -> Result<Vec<T>>
where
    <T as FromStr>::Err: Send,
    <T as FromStr>::Err: Sync,
    <T as FromStr>::Err: std::error::Error,
    <T as FromStr>::Err: 'static,
{
    data.split(sep)
        .map(|it| it.parse::<T>().context(format!("can't parse '{}'", it)))
        .collect()
}

#[derive(Debug)]
pub struct Foo(i32);

impl FromStr for Foo {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let i: i32 = s.parse()?;//.with_context(|| format!("parsing {:?}", s))?;
        Ok(Foo(i))
    }
}

fn main() -> Result<()> {

    // works for standart types
    println!("{:?}", split_parse::<i32>("100,200,300", ",")?);

    // FromStr for Foo also works
    println!("{:?}", "100".parse::<Foo>()?);
    
    // std::error::Error` is not implemented for `anyhow::Error`
    println!("{:?}", split_parse::<Foo>("100,200,300", ",")?);
    
    Ok(())
}

There are some non-public traits involved in Context conformances so I think the simplest solution is just to explicitly ask for the Context bound on Result

pub fn split_parse<T: FromStr>(data: &str, sep: &str) -> Result<Vec<T>>
where
    <T as FromStr>::Err: Send,
    <T as FromStr>::Err: Sync,
    Result<T, <T as FromStr>::Err>: Context<T, <T as FromStr>::Err>,
    <T as FromStr>::Err: 'static,

Full example:

Playground

use anyhow::{Context, Result};
use std::str::FromStr;

pub fn split_parse<T: FromStr>(data: &str, sep: &str) -> Result<Vec<T>>
where
    <T as FromStr>::Err: Send,
    <T as FromStr>::Err: Sync,
    Result<T, <T as FromStr>::Err>: Context<T, <T as FromStr>::Err>,
    <T as FromStr>::Err: 'static,
{
    data.split(sep)
        .map(|it| it.parse::<T>().context(format!("can't parse '{}'", it)))
        .collect()
}

#[derive(Debug)]
pub struct Foo(i32);

impl FromStr for Foo {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let i: i32 = s.parse()?; //.with_context(|| format!("parsing {:?}", s))?;
        Ok(Foo(i))
    }
}

fn main() -> Result<()> {
    // works for standart types
    println!("{:?}", split_parse::<i32>("100,200,300", ",")?);

    // FromStr for Foo also works
    println!("{:?}", "100".parse::<Foo>()?);

    // std::error::Error` is not implemented for `anyhow::Error`
    println!("{:?}", split_parse::<Foo>("100,200,300", ",")?);

    Ok(())
}
2 Likes

It's interesting that that made it possible to also remove other constraints on Err as they are now derived from this one single constraint.

1 Like