Skip to main content

grpcurl_core/
codec.rs

1use prost::Message;
2use prost_reflect::{DynamicMessage, MessageDescriptor};
3use tonic::codec::{BufferSettings, Codec, Decoder, Encoder};
4use tonic::Status;
5
6/// A gRPC codec for prost-reflect DynamicMessage.
7///
8/// Unlike tonic's ProstCodec which works with compile-time generated types,
9/// this codec works with runtime-resolved message descriptors, enabling
10/// dynamic RPC invocation without pre-compiled service stubs.
11pub struct DynamicCodec {
12    request_desc: MessageDescriptor,
13    response_desc: MessageDescriptor,
14}
15
16impl DynamicCodec {
17    pub fn new(request_desc: MessageDescriptor, response_desc: MessageDescriptor) -> Self {
18        DynamicCodec {
19            request_desc,
20            response_desc,
21        }
22    }
23}
24
25impl Codec for DynamicCodec {
26    type Encode = DynamicMessage;
27    type Decode = DynamicMessage;
28    type Encoder = DynamicEncoder;
29    type Decoder = DynamicDecoder;
30
31    fn encoder(&mut self) -> Self::Encoder {
32        DynamicEncoder {
33            _request_desc: self.request_desc.clone(),
34        }
35    }
36
37    fn decoder(&mut self) -> Self::Decoder {
38        DynamicDecoder {
39            response_desc: self.response_desc.clone(),
40        }
41    }
42}
43
44/// Encodes DynamicMessage into protobuf wire format.
45pub struct DynamicEncoder {
46    _request_desc: MessageDescriptor,
47}
48
49impl Encoder for DynamicEncoder {
50    type Item = DynamicMessage;
51    type Error = Status;
52
53    fn encode(
54        &mut self,
55        item: Self::Item,
56        dst: &mut tonic::codec::EncodeBuf<'_>,
57    ) -> Result<(), Self::Error> {
58        item.encode(dst)
59            .map_err(|e| Status::internal(format!("failed to encode request: {e}")))?;
60        Ok(())
61    }
62
63    fn buffer_settings(&self) -> BufferSettings {
64        BufferSettings::default()
65    }
66}
67
68/// Decodes protobuf wire format into DynamicMessage.
69pub struct DynamicDecoder {
70    response_desc: MessageDescriptor,
71}
72
73impl Decoder for DynamicDecoder {
74    type Item = DynamicMessage;
75    type Error = Status;
76
77    fn decode(
78        &mut self,
79        src: &mut tonic::codec::DecodeBuf<'_>,
80    ) -> Result<Option<Self::Item>, Self::Error> {
81        let msg = DynamicMessage::decode(self.response_desc.clone(), src)
82            .map_err(|e| Status::internal(format!("failed to decode response: {e}")))?;
83        Ok(Some(msg))
84    }
85
86    fn buffer_settings(&self) -> BufferSettings {
87        BufferSettings::default()
88    }
89}