capnproto-rust icon indicating copy to clipboard operation
capnproto-rust copied to clipboard

Reading raw enum value and setting on a builder

Open bluk opened this issue 4 years ago • 3 comments

Suppose I have a capnproto enum definition. Is there any way to get the raw u16 value of the enum and set the same raw u16 value on a builder as an enum field's value?

The idea is that I am using different versions of the capnproto definitions. The original definition has an enum with a few variants. It also has two struct definitions which each have a field with the enum type. First, I have application A with the original protocol definition. Later, I evolve the protocol and add more variants to an enum definition and use the new definitions in a different application B which sends messages to application A.

Application A could be a proxy or logging application. For instance, it could be an application that is copying an inbound message's enum value, and then setting the enum value on a different message.

I understand there would be some risks with allowing any u16 value to be set.

bluk avatar Mar 26 '21 05:03 bluk

You can get the raw u16 value via the ToU16 trait, which is implemented by all generated enums: https://github.com/capnproto/capnproto-rust/blob/aa09220f26ed6df5af76cefc804879bdf6aacdcc/capnp/src/traits.rs#L98

There is currently no supported way to set an enum to an arbitrary u16 value. You could try std::mem::transmute(), but I'd be worried about potential undefined behavior.

dwrensha avatar Mar 26 '21 12:03 dwrensha

Looking at generated code, the enum getters are like get_field(self) -> Result<EnumType, NotInSchema>. If the protocol evolved with more enum variants, then I assume that application A (with the original protocol without the new variants) will always get Err(NotInSchema) for any message set with a new variant value.

I was thinking about modifying the code generator to also add methods (only for enum fields) like:

pub fn set_field_raw(&mut self, value: u16);
pub fn get_field_raw(self) -> u16;

Is that feasible or ill-advised? If it's ok, I can also try to submit a PR.

bluk avatar Mar 26 '21 14:03 bluk

Adding new methods like that makes sense to me. I would slightly adjust the naming:

pub fn set_raw_field(&mut self, value: u16);
pub fn get_raw_field(self) -> u16;

That way, set_raw_ and get_raw_ are just new prefixes like the existing get_, set_ and init_.

dwrensha avatar Mar 27 '21 13:03 dwrensha