Codegen ergonomics: message construction
I do a lot of:
// get internal struct from somewhere
let mystruct = GetMyStruct::get();
let mut req = Req::new();
// now convert that struct anually to the request
req.set_foo(mystruct.foo);
req.set_bar(mystruct.bar);
This becomes very tedious, so I have a couple of suggestions:
Constructor with field params
it would be nice if I could have a constructor method like:
let req = Req::with(mystruct.foo, mystruct.bar);
and pass in the message fields as params.
Generic Conversion Trait
Similarly, it would be really great if codegen spit out something like:
trait ConvertInto<T> {
fn convert_into(t: Self) -> T;
}
impl From<T: ConvertInto<Req>> for Req {
fn from(t: T) -> Self {
T::convert_into(t)
}
}
Or something like that; I think you get the idea.
This way in my crate/upstream clients only have to impl ConvertInto<Req> for their internal datatypes, and can get conversion encapsulated in a single space (and protects refactoring somewhat by shielding struct changes, etc.) by essentially doing:
impl ConvertInto<Req> for Mystruct {
fn convert_into(t: Mystruct) -> Req {
let mut req = Req::new();
req.foo = mystruct.foo;
req.bar = mystruct.bar;
req
}
}
...
// which yields this nice code:
let req = GetMystruct::get().into();
Thanks for the suggestion, I believe you can impl From<Mystruct> for Req directly.
Wouldn't I have to do this in the generated code directly, otherwise this violates coherency, no?
Lol you're totally right; I forgot it's only coherency at the crate level, not module level :P
Ok so scratch second idea :P
As for the first idea, I agree it's a better way to construct messages that have a few fields. However the code for a message is not generated by grpc-rust plugin, it's generated by rust-protobuf plugin. All grpc-rust plugin handles are the service parts. So maybe you want to raise an issue to the the project.