use bytes::{Buf, BufMut, Bytes, BytesMut}; use http_body::Body; use roto_runtime::RotoMessage; use std::marker::PhantomData; use std::pin::Pin; use std::sync::Mutex; use std::task::{Context, Poll}; use tonic::codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}; pub mod generated { pub mod helloworld; pub mod interop; } pub struct RotoCodec { _phantom: PhantomData<(T, U)>, } impl Default for RotoCodec { fn default() -> Self { Self { _phantom: PhantomData, } } } impl Codec for RotoCodec where T: RotoMessage + Send + 'static, U: RotoMessage + Send + 'static, { type Encode = U; type Decode = T; type Encoder = RotoEncoder; type Decoder = RotoDecoder; fn encoder(&mut self) -> Self::Encoder { RotoEncoder(PhantomData) } fn decoder(&mut self) -> Self::Decoder { RotoDecoder(PhantomData) } } pub struct RotoEncoder(PhantomData); impl Encoder for RotoEncoder where U: RotoMessage, { type Item = U; type Error = tonic::Status; fn encode(&mut self, message: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { buf.put_slice(&message.bytes()); Ok(()) } } pub struct RotoDecoder(PhantomData); impl Decoder for RotoDecoder where T: RotoMessage, { type Item = T; type Error = tonic::Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { if buf.remaining() == 0 { return Ok(None); } let bytes = buf.copy_to_bytes(buf.remaining()); match T::decode(bytes) { Ok(msg) => Ok(Some(msg)), Err(e) => Err(tonic::Status::internal(format!("Roto decode error: {}", e))), } } } pub struct BufferPool { pool: Mutex>, default_capacity: usize, } impl BufferPool { pub fn new(default_capacity: usize) -> Self { Self { pool: Mutex::new(Vec::new()), default_capacity, } } pub fn get(&self) -> BytesMut { self.pool .lock() .unwrap() .pop() .unwrap_or_else(|| BytesMut::with_capacity(self.default_capacity)) } pub fn put(&self, mut buf: BytesMut) { buf.clear(); if buf.capacity() >= self.default_capacity { self.pool.lock().unwrap().push(buf); } } } pub struct StatusBody { pub data: Option, pub trailers: Option, } impl StatusBody { pub fn new(data: Option, status: u8) -> Self { let mut trailers = http::HeaderMap::new(); trailers.insert("grpc-status", status.to_string().parse().unwrap()); Self { data, trailers: Some(trailers), } } } impl Body for StatusBody { type Data = Bytes; type Error = tonic::Status; fn poll_frame( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { if let Some(data) = self.data.take() { Poll::Ready(Some(Ok(http_body::Frame::data(data)))) } else if let Some(trailers) = self.trailers.take() { Poll::Ready(Some(Ok(http_body::Frame::trailers(trailers)))) } else { Poll::Ready(None) } } }