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

serde_json multi-typed literal parsing #308

Open
nyurik opened this issue Sep 24, 2024 · 5 comments
Open

serde_json multi-typed literal parsing #308

nyurik opened this issue Sep 24, 2024 · 5 comments
Labels

Comments

@nyurik
Copy link

nyurik commented Sep 24, 2024

I am implementing #[attr(default = <literal>)], and my value can be multi-typed depending on what it gets attached to. The serde_json::Value is the format I will eventually have to work with. Darling seem to have the needed from_value() functions, but I am not too certain how to use it to convert from a syn::Lit into serde_json::Value, possibly via some magical match statement? Thx!

@TedDriggs
Copy link
Owner

I'm afraid there's no magical match statement - you'll need to write your own that looks at each Lit variant, gets its value, then uses the .into() conversion for it. How complex that will be depends on how many kinds of JSON value you want to allow, and whether you're going to require it be a literal or would accept any expression that produces impl Into<serde_json::Value>.

Your simplest approach might be this:

#[derive(FromMeta)]
struct Receiver {
    #[darling(with = preserve_str_literal)]
    default: syn::Expr,
}

Then in the code you generate from this, you'd use default by writing...

let default_expr = self.default;
quote_spanned!(default_expr.span()=>serde_json::Value::from(#default_expr));

This allows any input that evaluates to something which can be converted to a JSON value.

@nyurik
Copy link
Author

nyurik commented Oct 3, 2024

@TedDriggs thank you so much for your help! Everything works great, except that it now a required field. Is it possible to have optional expressions, to parse things like #[arg(special)] (no default param)?

#[derive(FromMeta)]
struct Receiver {
    #[darling(with = preserve_str_literal)]
    default: Option<syn::Expr>,
    special: Option<bool>,
}

@nyurik
Copy link
Author

nyurik commented Oct 3, 2024

Alternatively, perhaps it might make sense to simplify the API, and use dedicated virtual attributes:

// `param` has two attributes, one "bool" and one with an aribtrary value
fn foo(  #[default("value")]  #[special]  param: String  )

Is this type of parsing possible?

@TedDriggs
Copy link
Owner

darling is designed for serde-style attributes, where there is an outer namespace and then modifiers are placed within that. As a result, checking for something like #[special] isn't well-supported; you have to do a bunch of work by hand to identify that.

@TedDriggs
Copy link
Owner

Is it possible to have optional expressions, to parse things like #[arg(special)] (no default param)?

That should just work already: If default isn't set by the caller of your macro, that field will fall back to calling <Option<syn::Expr> as FromMeta>::from_none, which will return Some(None), so the caller won't get an error in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants