Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling set_singular_field on dynamic message with generated descriptor #741

Open
rellfy opened this issue Sep 26, 2024 · 1 comment
Open

Comments

@rellfy
Copy link

rellfy commented Sep 26, 2024

The scenario I am working with is that clients may upload a dynamic proto file, which may follow a specific schema of reserved fields that is generated on the server.

Therefore, if the dynamic client-uploaded schema contains a reserved field name, the server creates it using the generated field from the static server files (which defines the reserved fields). For example, let's say that the message Reserved and field name reserved are reserved as a special field. Assume the dynamic client message is ClientMessage:

// This is defined by the client, and may or may not
// include the Reserved message. If it does, the server
// will include it when creating the dynamic message.
message ClientMessage {
    Reserved reserved = 1;
    double foo = 2;
}

// This is also defined and generated in the server.
message Reserved {
    double bar = 1;
}

on the server something like this happens:

// Generate the dynamic message
let mut input_message = input_message_descriptor.new_instance();
let args_hashmap = self.args_hashmap();
for (field, value) in &args_hashmap {
    // ... set some fields on the user-defined dynamic message.
    field.set_singular_field(&mut *input_message, parsed_input);
}
// Now, set the values for reserved fields (as defined by the generated server schema)
// if they have been declared in this client message.
let reserved_field_opt = input_message_descriptor.field_by_name("reserved");  
if let Some(reserved_field) = reserved_field_opt {
    // This is an instance from the server-generated type.
    // The schema matches the client .proto dynamic message.
    // (if not, a runtime error would be fine).
    let mut reserved = Reserved::new();
    // ... populate the reserved struct.
    // Set the field on the dynamic message.
    // This panics, because the Reserved type is
    // generated, while the `reserved` field is dynamic,
    // even though the schemas match.
    reserved_field.set_singular_field(  
        &mut *input_message,  
        ReflectValueBox::Message(Box::new(reserved)),  
    );
}

This panics on protobuf/src/reflect/dynamic/optional.rs line 29:

assert_eq!(value.get_type(), self.elem);

I believe it panics because one message is generated while the other is dynamic, but since the schema matches it should not panic IMO.

So my question would be, is there a way to be able to use a generated type to apply to set_singular_field on a dynamic field? Maybe serializing the generated type and de-serializing as the dynamic would work, but this seems an inefficient way to do it.

If I simply comment out the assert_eq above and link the package locally, it works fine.

My first thought to address this would be to replace the assert_eq, or the equality implementation for the types, with something that checks the underlying schema only.

@rellfy
Copy link
Author

rellfy commented Sep 26, 2024

To clarify, I am currently setting all these values dynamically, without using the generated Reserved struct. But it would be much nicer to be able to use the generated struct as it is significantly less code to set all the fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant