Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support error-chain #581

Closed
bbigras opened this issue Sep 10, 2017 · 7 comments
Closed

support error-chain #581

bbigras opened this issue Sep 10, 2017 · 7 comments
Milestone

Comments

@bbigras
Copy link

bbigras commented Sep 10, 2017

I think only impl std::fmt::Display and std::error::Error are needed.

To test, this code should build:

#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;

extern crate nom;

mod errors {
    error_chain! {
        foreign_links {
            Nom(::nom::IError);
        }
    }
}

use errors::*;

fn main() {
    println!("Hello, world!");
}

currently the output is:

error[E0599]: no method named `cause` found for type `&nom::IError` in the current scope
  --> src\main.rs:11:5
   |
11 | /     error_chain! {
12 | |         foreign_links {
13 | |             Nom(::nom::IError);
14 | |         }
15 | |     }
   | |_____^
   |
   = note: this error originates in a macro outside of the current crate

error[E0277]: the trait bound `nom::IError: std::fmt::Display` is not satisfied
  --> src\main.rs:11:5
   |
11 | /     error_chain! {
12 | |         foreign_links {
13 | |             Nom(::nom::IError);
14 | |         }
15 | |     }
   | |_____^ `nom::IError` cannot be formatted with the default formatter; try using `:?` instead if you are using a for
mat string
   |
   = help: the trait `std::fmt::Display` is not implemented for `nom::IError`
   = note: required because of the requirements on the impl of `std::fmt::Display` for `&nom::IError`
   = note: required by `std::fmt::Display::fmt`
   = note: this error originates in a macro outside of the current crate

error[E0277]: the trait bound `nom::IError: std::error::Error` is not satisfied
  --> src\main.rs:11:5
   |
11 | /     error_chain! {
12 | |         foreign_links {
13 | |             Nom(::nom::IError);
14 | |         }
15 | |     }
   | |_____^ the trait `std::error::Error` is not implemented for `nom::IError`
   |
   = note: required by `std::error::Error::description`
   = note: this error originates in a macro outside of the current crate

error: aborting due to 3 previous errors

error: Could not compile `test-chain`.

To learn more, run the command again with --verbose.

Something like 5bde059 but better.

bbigras added a commit to bbigras/squad-broadcasts that referenced this issue Sep 10, 2017
@Geal
Copy link
Collaborator

Geal commented Oct 30, 2017

Hello,

nom 4.0 should be easier to use with error-chain, since its main type will be a Result. Please test with the branch named "result" to see if it would work

@Geal Geal added this to the 4.0 milestone Oct 30, 2017
@bbigras
Copy link
Author

bbigras commented Oct 30, 2017

I tested it and it seems I can't do the following because the error_chain! macro doesn't support lifetimes. (see rust-lang-deprecated/error-chain#219)

If you want a clonable exemple https://github.com/bbigras/nom-error-chain

error_chain! {
    foreign_links {
        Nom(::nom::Err<&str>);
    }
}

@Etherian
Copy link

Try derive-error-chain. I don't know how well it handles lifetimes, but it tends to be less temperamental in general. Note, however, that there is talk of it merging with error-chain.

@siler
Copy link

siler commented Feb 28, 2018

This issue isn't resolved with derive-error-chain. I ended up creating a new error type and surround every call to a nom parser with a macro that uses .map_err to convert the nom error into the new error type.

@bbigras
Copy link
Author

bbigras commented Mar 1, 2018

I use failure now. nom doesn't seem to support it and since I'm lazy I use:

fn nom_err(e: nom::IError) -> Error {
    match e {
        nom::IError::Error(e) => err_msg(e.description().to_string()),
        nom::IError::Incomplete(_) => err_msg("incomplete"),
    }
}

parse_with_nom(&data).to_full_result().map_err(nom_err)?;

@ivanovaleksey
Copy link

ivanovaleksey commented Mar 4, 2018

Hello, I have faced with this issue too.
I also have a plan to switch to failure, however, I would like to do it a little bit later (I need some time to learn it, and I don't have this time right time).
@siler could you please show me your implementation?

I end up with the following

errors {
    Nom(kind: ::nom::ErrorKind) {
        description("parsing error")
        display("parsing error: {:?}", kind)
    }
}


impl<'a> From<::nom::Err<::nom::types::CompleteStr<'a>>> for Error {
    fn from(err: ::nom::Err<::nom::types::CompleteStr<'a>>) -> Error {
        let kind = err.into_error_kind();
        Error::from_kind(ErrorKind::Nom(kind))
    }
}

Not sure if it is a right way.

@siler
Copy link

siler commented Mar 7, 2018

Mine is more similar to @bbigras' solution:

#[derive(Debug, ErrorChain)]
pub enum ErrorKind {
    #[error_chain(foreign)]
    Nom(NomError)
}

#[derive(Debug)]
pub struct NomError {
    desc: String,
}

impl<E: fmt::Debug + Clone> From<nom::Err<E>> for NomError {
    fn from(error: nom::Err<E>) -> Self {
        let desc = match error {
            nom::Err::Incomplete(needed) => format!("ran out of bytes: {:?}", needed),
            nom::Err::Error(context) => format!("{:?}", nom::error_to_list(&context)),
            nom::Err::Failure(context) => format!("{:?}", nom::error_to_list(&context)),
        };

        NomError { desc }
    }
}

macro_rules! nom {
    ($expr:expr) => {
        $expr.map_err(NomError::from)
    }
}

// For example:
let short = nom!(be_u16(bytes))?;

@Geal Geal closed this as completed May 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants