colin-kiegel / rust-derive-builder

derive builder implementation for rust structs
https://colin-kiegel.github.io/rust-derive-builder/
Apache License 2.0
1.32k stars 88 forks source link

Setting values from a slice #210

Closed v1gnesh closed 3 years ago

v1gnesh commented 3 years ago

Hi,

Using the below example code as reference

struct Channel {
    token: i32,
    special_info: i32,
}

Can a struct field have a type of enum, in addition to supporting numbers or strings?

fn main() {
    // builder pattern, go, go, go!...
    let ch = ChannelBuilder::default()
        .special_info(42u8)
        .token(19_124)
        .build()
        .unwrap();
    println!("{:?}", ch);
}

Can the builder be updated to allow reading/consuming from a slice input &mut R where R: BufRead or &mut &[u8]

Rather than specifying values directly in the setter functions, can support be added to do something like:

fn main() {
    // builder pattern, go, go, go!...
    let ch = ChannelBuilder::default()
        .special_info(data.read_be()?)
        .token(data.read_be()?)
        .build()
        .unwrap();
    println!("{:?}", ch);
}

where the field type of special_info etc., from the struct definition will decide how many bytes to read. Also, can there be a way to avoid repeated data.read_be()? as input parms to the setter functions?

read_be() is a reference from https://crates.io/crates/eio

Another possibly dumb question: Why is the ::default() bit there? Is it just to allow adding our own default functions?

Can this default function be used to support the above use case of reading from a mutable input slice? Allowing non-hard-coded setter parms, so that they're set from the input slice/source that's being parsed.

TedDriggs commented 3 years ago

What you describe is deserialization, which is more commonly done with the excellent serde crate. A single struct can derive both Builder and Deserialize, so you wouldn't need derive_builder if data is in a serde-compatible format.

You have three pretty good options, depending on your particular use-case:

All of those are better fits conceptually and practically for this use-case, so it's not something we'll add to derive_builder.

Why is the ::default() bit there?

The ChannelBuilder is a type, not a value. The special_info method takes a value self (or &mut self or &self, depending on the builder pattern) as its first parameter so that it has a place to store the field value it was just passed. The initial call to default creates the self that is then passed to special_info.

Some people (myself included) like to add a method like this:

impl Channel {
    pub fn builder() -> ChannelBuilder {
        ChannelBuilder::default()
    }
}

That way, someone can use my_crate::Channel; and make a value of the builder type without an additional import.