Skip to main content

grpc_webnext/
codec.rs

1//! A tonic [`Codec`] that passes message bytes through untouched.
2//!
3//! This is what makes the proxy schema-agnostic: tonic handles the gRPC
4//! length-prefix framing and hands us exactly one message body per `decode`
5//! call, so we never need the `.proto` to forward `+proto` payloads.
6
7use bytes::{Buf, BufMut, Bytes};
8use tonic::codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder};
9use tonic::Status;
10
11/// Encodes/decodes gRPC messages as opaque [`Bytes`].
12#[derive(Debug, Clone, Default)]
13pub struct BytesCodec;
14
15impl Codec for BytesCodec {
16    type Encode = Bytes;
17    type Decode = Bytes;
18    type Encoder = BytesEncoder;
19    type Decoder = BytesDecoder;
20
21    fn encoder(&mut self) -> Self::Encoder {
22        BytesEncoder
23    }
24    fn decoder(&mut self) -> Self::Decoder {
25        BytesDecoder
26    }
27}
28
29#[derive(Debug)]
30pub struct BytesEncoder;
31
32impl Encoder for BytesEncoder {
33    type Item = Bytes;
34    type Error = Status;
35
36    fn encode(&mut self, item: Bytes, dst: &mut EncodeBuf<'_>) -> Result<(), Status> {
37        dst.put_slice(&item);
38        Ok(())
39    }
40}
41
42#[derive(Debug)]
43pub struct BytesDecoder;
44
45impl Decoder for BytesDecoder {
46    type Item = Bytes;
47    type Error = Status;
48
49    fn decode(&mut self, src: &mut DecodeBuf<'_>) -> Result<Option<Bytes>, Status> {
50        // tonic limits `src` to exactly one message body (possibly empty).
51        let len = src.remaining();
52        Ok(Some(src.copy_to_bytes(len)))
53    }
54}