//! A [`tonic::Codec`](https://docs.rs/tonic/0.11.0/tonic/codec/trait.Codec.html) //! that implements `application/grpc+proto` via the rust-protobuf. #[cfg(feature = "protobuf-v3")] mod protobuf_v3 { use std::marker::PhantomData; use bytes::{Buf, BufMut}; use protobuf::Message; use tonic::{ codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, Code, Status, }; /// A [`Codec`] that implements `application/grpc+proto` via the [rust-protobuf v3](https://crates.io/crates/protobuf) library. #[derive(Debug, Clone, Default)] pub struct ProtobufCodecV3 { _pd: PhantomData<(T, U)>, } impl Codec for ProtobufCodecV3 where T: Message + Send + 'static, U: Message + Default + Send + 'static, { type Encode = T; type Decode = U; type Encoder = ProtobufEncoderV3; type Decoder = ProtobufDecoderV3; fn encoder(&mut self) -> Self::Encoder { ProtobufEncoderV3 { _pd: PhantomData } } fn decoder(&mut self) -> Self::Decoder { ProtobufDecoderV3 { _pd: PhantomData } } } /// A [`Encoder`] that knows how to encode `T`. #[derive(Debug, Clone, Default)] pub struct ProtobufEncoderV3 { _pd: PhantomData, } impl Encoder for ProtobufEncoderV3 { type Item = T; type Error = Status; fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { let mut writer = buf.writer(); item.write_to_writer(&mut writer) .expect("Message only errors if not enough space"); Ok(()) } } /// A [`Decoder`] that knows how to decode `U`. #[derive(Debug, Clone, Default)] pub struct ProtobufDecoderV3 { _pd: PhantomData, } impl ProtobufDecoderV3 { /// Get a new decoder with explicit buffer settings pub fn new() -> Self { Self { _pd: PhantomData } } } impl Decoder for ProtobufDecoderV3 { type Item = U; type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { let mut reader = buf.reader(); let item = ::parse_from_reader(&mut reader).map_err(from_decode_error)?; Ok(Some(item)) } } fn from_decode_error(error: protobuf::Error) -> Status { // Map Protobuf parse errors to an INTERNAL status code, as per // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md Status::new(Code::Internal, error.to_string()) } } #[cfg(feature = "protobuf-v3")] pub use protobuf_v3::*; #[cfg(feature = "protobuf-v2")] mod protobuf_v2 { use std::marker::PhantomData; use bytes::{Buf, BufMut}; use protobuf2::Message; use tonic::{ codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, Code, Status, }; /// A [`Codec`] that implements `application/grpc+proto` via the [rust-protobuf v2](https://crates.io/crates/protobuf/2.28.0) library. #[derive(Debug, Clone, Default)] pub struct ProtobufCodecV2 { _pd: PhantomData<(T, U)>, } impl Codec for ProtobufCodecV2 where T: Message + Send + 'static, U: Message + Default + Send + 'static, { type Encode = T; type Decode = U; type Encoder = ProtobufEncoderV2; type Decoder = ProtobufDecoderV2; fn encoder(&mut self) -> Self::Encoder { ProtobufEncoderV2 { _pd: PhantomData } } fn decoder(&mut self) -> Self::Decoder { ProtobufDecoderV2 { _pd: PhantomData } } } /// A [`Encoder`] that knows how to encode `T`. #[derive(Debug, Clone, Default)] pub struct ProtobufEncoderV2 { _pd: PhantomData, } impl Encoder for ProtobufEncoderV2 { type Item = T; type Error = Status; fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { let mut writer = buf.writer(); item.write_to_writer(&mut writer) .expect("Message only errors if not enough space"); Ok(()) } } /// A [`Decoder`] that knows how to decode `U`. #[derive(Debug, Clone, Default)] pub struct ProtobufDecoderV2 { _pd: PhantomData, } impl ProtobufDecoderV2 { /// Get a new decoder with explicit buffer settings pub fn new() -> Self { Self { _pd: PhantomData } } } impl Decoder for ProtobufDecoderV2 { type Item = U; type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { let mut reader = buf.reader(); #[allow(deprecated)] let item = protobuf2::parse_from_reader(&mut reader).map_err(from_decode_error)?; Ok(Some(item)) } } fn from_decode_error(error: protobuf2::error::ProtobufError) -> Status { // Map Protobuf parse errors to an INTERNAL status code, as per // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md Status::new(Code::Internal, error.to_string()) } } #[cfg(feature = "protobuf-v2")] pub use protobuf_v2::*;