'Unable to implement custom enum wrapper for std::error::Error

I am trying to figure out how the error enum works to wrap std::error:Error by passing in bad input for Url. I wish to wrap url::ParseError.

use std::error::Error;
use std::fmt::Display;

#[derive(Debug)]
pub enum WordCount {
    UrlError(url::ParseError),
}

impl Display for WordCount {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            WordCount::UrlError(e) => {
                write!(f, "{}", e)
            },
        }
    }
}

impl std::error::Error for WordCount {}

impl From<url::ParseError> for WordCount {
    fn from(err: url::ParseError) -> Self {
        WordCount::UrlError(err)
    }
} 

pub fn run() -> Result<String, WordCount> {
    let args: Vec<String> = env::args().collect();
    let arg = &args[1].as_ref();
    let domain = Url::parse(arg);

    match domain {
        Ok(_) => {}
        Err(err) => return Err(WordCount::UrlError(err)),
   };

    Ok("".to_owned())
}

If I replace the following line: Err(err) => return Err(WordCount::UrlError(err)), in the fn run()

with: panic!("some string") e.g

   match domain {
    Ok(domain) => println!("happy domain"),
    Err(err) => panic!("panicking"),
};

Then I can see an error print to the terminal. But not with the implementation, nothing prints to stderr even if I have implemented Display.



Solution 1:[1]

Just returning an error doesn't implicetly print it. You could make your main function to return the same error, then your program will report the message at the end of execution. As an example:

use url::Url;
use std::error::Error;
use std::fmt::Display;

#[derive(Debug)]
pub enum CrawlerError {
    UrlError(url::ParseError),
}

impl Display for CrawlerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            CrawlerError::UrlError(e) => {
                write!(f, "{}", e)
            },
        }
    }
}

impl std::error::Error for CrawlerError {}

impl From<url::ParseError> for CrawlerError {
    fn from(err: url::ParseError) -> Self {
        CrawlerError::UrlError(err)
    }
} 

pub fn run() -> Result<String, CrawlerError> {
    let domain = Url::parse("foo/bar");

    match domain {
        Ok(_) => Ok("".to_string()),
        Err(err) => Err(CrawlerError::UrlError(err)),
   }

}

fn main() -> Result<(), CrawlerError> {
    run()?;
    Ok(())
}

Playground

Results:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 1.25s
     Running `target/debug/playground`
Error: UrlError(RelativeUrlWithoutBase)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1