Applying macro to external struct to generate impl


I'm in need of getting builders for a lot of structs from an external crate. I know I could do myself by hand (not using external libs like derive_builder and typed_builder), however, since there are many many structs, I'd like to write a macro to do that work for me.

I'm not too confident that is possible, as far as I know, macros operate on token streams (or some form of pattern matching with macro_rules!), so they have limited semantic information?

Ideally, I'd love to be able to do something along the lines of:

// or even better, although certainly impossible x)

Which would expand to:

impl Builder for SomeStruct {
  fn field(...) { ... }

Saving me a ton of hand typing.

I have a bit of hope, seeing serde has a remote derive functionality that somehow checks whether the local definition matches the remote definition?

At compile time, Serde will check that all the fields in the definition you provided match the fields in the remote type.

Is this at all possible? If not, what is the closest thing?
Thank you all in advance :slight_smile:

Macros operate on a token stream and can only access to whatever you pass them. builder(SomeStruct) gets SomeStruct as input and nothing else. remote-derivie gets passed a type implementation that must match remote type and solves a slightly different problem.

1 Like

Yeah, that's what I thought. But I wonder, how does remote derive assert the local type matches the remote one? It only gets a string as well (#[serde(remote = "Type")]).

with remote derive you're not only giving it the name of the remote type, but also the fields it has.

#[derive(Serialize, Deserialize)]
#[serde(remote = "Duration")]
struct DurationDef {
    secs: i64,
    nanos: i32,

it simply uses the field names it gets from the DurationDef struct, and uses them to generate code pointing to the type specified in the remote = "Duration" part. If you give fields in DurationDef that don't exist in Duration, it fails to compile simply because the fields don't exist, and the generated code is invalid because it's trying to reference fields that don't exist. There's no magic assertions going on.

1 Like

Ahh I see, that makes sense. It's just spitting code using the local field names in the hopes it matches the remote type.

So yeah, there's no way to achieve what I was thinking of, quite a shame :frowning:
Adding builders to the external crate itself is not really an option, so what would you suggest doing? Writing the builders by hand (or writing something to generate the code for me; build script maybe?)

Thank you for your info so far :slight_smile:

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.