Skip to content

DynamicMessage::from_message round-trips through bytes, panics on mismatch, and needs a hand-resolved MessageIndex #413

Description

@iainmcgin

DynamicMessage::from_message is the only road from a generated Message value to reflection, and it has two costs a caller cannot avoid:

  • it encodes the whole message to a Vec<u8> and decodes it again against the descriptor, so a library that evaluates over a request struct it already holds pays an encode plus a full decode on every call;
  • it takes a MessageIndex the caller has to resolve by hand from the pool (strip a leading dot, look the full name up), and it panics on a descriptor mismatch instead of returning an error, so a pool that was built from a different .proto revision than the generated code turns into a process abort rather than a DecodeError.
pub fn from_message<M: Message>(msg: &M, pool: Arc<DescriptorPool>, msg_idx: MessageIndex) -> Self {
    let bytes = msg.encode_to_vec();
    Self::decode(pool, msg_idx, &bytes)
        .expect("generated message must round-trip through its own descriptor")
}

What would close the gap, in increasing order of ambition:

  1. A fallible variant, try_from_message, that returns the DecodeError and leaves the panicking one as a thin wrapper (or deprecates it).
  2. Index resolution from the type itself: with M: Message + MessageName the full name is M::PACKAGE + M::NAME, so the caller should not need to look up the MessageIndex at all — try_from_message(msg, pool) with a DecodeError/NotFound when the pool lacks the type.
  3. A road that does not re-encode: either a generated-code reflection hook (each generated message can walk its own fields against its descriptor and populate the dynamic field map directly), or a borrowed reflective view over &M that answers field-by-field reads without materialising a DynamicMessage. This is what makes reflection over a message the host already owns cheap enough to use per request.

Items 1 and 2 are small and additive. Item 3 is the real gap and probably wants a design note first; happy to sketch one if there is appetite.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions