TedDriggs / darling

A Rust proc-macro attribute parser
MIT License
1.02k stars 66 forks source link

Help needed: Creating an error inside custom "map" function #207

Closed lpotthast closed 1 year ago

lpotthast commented 1 year ago

Thank you all for this great crate! But a little help is needed here.

I have something like the following

fn parse_foo(string: Option<String>) -> Option<Foo> {
    string.map(|it| match fallible_operation(it) {
        Ok(foo) => foo,
        Err(err) => panic!("expected ..., Caused by: {err:?}"),
    })
}

#[derive(Debug, FromField)]
#[darling(attributes(my_attr))]
struct MyFieldReceiver {
    ident: Option<syn::Ident>,

    ty: syn::Type,

    #[darling(map = "parse_foo")]
    foo: Option<Foo>,
}

which works like expected, but obviously generates non-readable errors in case the panic route is taken.

Is it possible to generate a darling Error inside parse_foo instead which then automatically has the correct span information of the field attached and is part of darlings error collection?

It seems that I cannot just return Result<Option<Foo>>, using darlings Result type def`.

Additional question: Option<Foo> might as well just be Foo in my case. The attribute is optional, but if it is missing, a default can be computed based in the fields type. I currently just do

impl MyFieldReceiver {
    pub fn get_foo(&self) -> Foo{
        self.foo.unwrap_or_else(|| foo_default(&self.ty))
    }
}

It would be nice if this computation could be moved "up" into the creation of MyFieldReceiver, so that it does not need to be evaluated multiple times.

(I know that I could also take &mut self and compute if absent, but that still leaves me with the custom accessor function that I would rather get rid of)

Is it possible to use the "map" function and already have access to the (ident, type, ...) information of the field?

TedDriggs commented 1 year ago

Is it possible to generate a darling Error inside parse_foo instead which then automatically has the correct span information of the field attached and is part of darlings error collection?

Yes, use #[darling(and_then="...")] instead of map. I expect that would automatically apply the span information, but I'd suggest testing to confirm that.

Is it possible to use the "map" function and already have access to the (ident, type, ...) information of the field?

I don't think so; you could use a cell of some sort to avoid needing &mut self in the getter, but I'm not sure how you'd read the values of the parent field during a call to map or to default. You can see these custom getters in a lot of darling-consuming crates, primarily for the exact inheritance situation you're describing.