magiclen / educe

This crate offers procedural macros designed to facilitate the swift implementation of Rust's built-in traits.
MIT License
127 stars 11 forks source link

Set default per type #6

Closed jayvdb closed 8 months ago

jayvdb commented 1 year ago

I have some https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html and similar types used deeply within my own structs that I would like to add Default to. The structs are all generated.

I could generate literal values as mentioned at https://github.com/magiclen/educe#the-default-values-for-specific-fields, i.e #[educe(Default = 1)], but then I need the generator to know what field type it is, and in doing that I am almost at the point I dont need educe any more.

I am wondering whether it might be possible to have a mapping of type-name to default value, which educe uses as needed to get default literal values if there is none explicitly provided for each member.

e.g. something a bit like

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[educe(Default(literals = (Ipv4Addr = [0,0,0,0], Ipv6Addr = [0,0,0,0,...])))]
    pub struct Ipv4Range {
        #[educe(Default)]
        pub first: std::net::Ipv4Addr,
        pub last: std::net::Ipv4Addr,
    }
jayvdb commented 1 year ago

@magiclen, could I get your thoughts on this? I'm not great at macros, but I could take a crack at this if it is likely to get merged if I get it working.

magiclen commented 1 year ago

I'm not sure what you mean but for now I think you can just use

#[derive(Clone, Debug, Educe)]
#[educe(Default)]
pub struct Ipv4Range {
    #[educe(Default(expression = "[0, 0, 0, 0].into()"))]
    pub first: std::net::Ipv4Addr,
    #[educe(Default(expression = "[255, 255, 255, 255].into()"))]
    pub last: std::net::Ipv4Addr,
}
jayvdb commented 1 year ago

I am aware I can do that, but I was hoping to avoid having to modify the code generation of the members to add this to every member. It is easier if I can tell educe at the struct level macro invocation that "when it sees any "Ipv4Addr" member, here is the value it should use as the default".

magiclen commented 1 year ago

Okay, I see.

I have a question. How can you tell Ipv4Addr are the same struct or not? If the code is like this,

mod a {
    pub struct Ipv4Addr(u32);
}

struct Ipv4Addr;

#[derive(Clone, Debug)]
#[educe(Default(literals = (Ipv4Addr = [0,0,0,0], Ipv6Addr = [0,0,0,0,...])))]
pub struct Ipv4Range {
    #[educe(Default)]
    pub first: std::net::Ipv4Addr,
    pub last: Ipv4Addr,
}
jayvdb commented 1 year ago

I am doing codegen of the structs, so I know what types the members can be, and cant be. c.f. https://github.com/oxidecomputer/typify/pull/184