use protox::prost::bytes::{Buf, BufMut};
use std::marker::PhantomData;
use tonic::codec::{DecodeBuf, EncodeBuf};
use gin_tonic_core::{Message, decoder::Decoder, encoder::Encoder};
#[derive(Debug, Clone)]
pub struct GinCodec<T, U> {
_pd: PhantomData<(T, U)>,
}
impl<T, U> Default for GinCodec<T, U> {
fn default() -> Self {
Self { _pd: PhantomData }
}
}
#[derive(Debug, Clone)]
pub struct GinEncoder<T> {
_pd: PhantomData<T>,
}
#[derive(Debug, Clone)]
pub struct GinDecoder<U> {
_pd: PhantomData<U>,
}
impl<T, U> tonic::codec::Codec for GinCodec<T, U>
where
T: Message + Send + 'static + std::fmt::Debug,
U: Message + Send + 'static + std::fmt::Debug,
{
type Encode = T;
type Decode = U;
type Encoder = GinEncoder<T>;
type Decoder = GinDecoder<U>;
fn encoder(&mut self) -> Self::Encoder {
GinEncoder { _pd: PhantomData }
}
fn decoder(&mut self) -> Self::Decoder {
GinDecoder { _pd: PhantomData }
}
}
impl<T: Message + std::fmt::Debug> tonic::codec::Encoder for GinEncoder<T> {
type Item = T;
type Error = tonic::Status;
fn encode(&mut self, item: Self::Item, dst: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {
let size_hint = item.message_size_hint();
unsafe {
let slice = std::slice::from_raw_parts_mut(dst.chunk_mut().as_mut_ptr(), size_hint);
let mut encoder = Encoder::new(slice);
item.encode_message(&mut encoder);
dst.advance_mut(size_hint);
}
Ok(())
}
}
impl<U: Message + std::fmt::Debug> tonic::codec::Decoder for GinDecoder<U> {
type Item = U;
type Error = tonic::Status;
fn decode(&mut self, src: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {
let len = src.remaining();
let decoded =
Self::Item::decode_message(&mut Decoder::new(src.chunk())).map_err(map_core_err)?;
src.advance(len);
Ok(Some(decoded))
}
}
fn map_core_err(err: gin_tonic_core::ProtoError) -> tonic::Status {
tonic::Status::internal(err.to_string())
}