Nom5 returning trait objects

Hi

I am getting into a little bit of pickle with returning a trait object from a nom function.
I am not even sure what I want is possible.

I have a nom function like

fn scalar<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
    alt((ref, quoted_string, uri, boo,))(i)
}

This function returns a enum called Token which works fine.

What I want todo is to create a wrapper of type struct for each enum variant. All these wrappers will implement a trait called HVal.

Is it possible to define a nom function like below

fn val<'a>(i: &'a str) -> IResult<&'a str, Box<&dyn HVal>, (&'a str, ErrorKind)> {
    map(
        scalar,
        |t: Token| {
            let s: Scaler = Scaler::new(t);    // I would have different structs here based on token
            Box::new(&s)
        }   
    )(i)
}

I can't seem to return traits here

expected trait object dyn hval::HVal, found struct token::Scaler
|
= note: expected enum std::result::Result<(&'a str, std::boxed::Box<&'a (dyn hval::HVal + 'a)>), nom::internal::Err<(&'a str, nom::error::ErrorKind)>>
found enum std::result::Result<(&str, std::boxed::Box<&token::Scaler>), nom::internal::Err<(&str, nom::error::ErrorKind)>>

Is this possible ?

Thanks

The compiler is inferring the type of your closure differently than you want it to. Try explicitly casting your reference:
Box::new(&s as &dyn HVal)

Edit: There’s also going to be a lifetime problem...

1 Like

Thanks. That does work of course I now have

Box::new(&Scaler::new(t.clone()) as &dyn HVal)
    |             ^^^^^^^^^^----------------------^^^^^^^^^^^^^^
    |             |         |
    |             |         temporary value created here
    |             returns a value referencing data owned by the current function

which is a separate issue.

I’m pretty sure you want the type to be Box<dyn HVal> instead of Box<&dyn HVal>.

Got it going with

fn scalar_struct<'a>(i: &'a str) -> IResult<&'a str, Box<dyn HVal>, (&'a str, ErrorKind)> {
    map(
        alt((zinc_ref, quoted_string, uri, datetime, date, zinc_number, bool, na, null, marker, remove)),
        |t: Token| {
            Box::new(Scaler::new(t.clone())) as Box<dyn HVal>
        }   
    )(i)
}

Thanks

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.