pub use crate::config::EncodeSettings;
use std::marker::PhantomData;
use bytes::BufMut;
use tonic::{
Status,
codec::{BufferSettings, EncodeBuf},
};
use super::envelope::delimited;
use super::{DecodeSettings, Decoder, Event};
use crate::{MemorySize, MessageError, operations::StreamItem};
use harmos_domain::Portable;
use harmos_sdk::grpc::DecodeInput;
pub struct Codec<W, D, E> {
decoder: Decoder<W, D>,
encode: EncodeSettings,
response: PhantomData<fn() -> E>,
}
pub struct Encoder<W, E> {
settings: EncodeSettings,
scratch: Vec<u8>,
response: PhantomData<fn() -> (W, E)>,
}
pub struct Transcoded;
pub trait Wire<T>: Send + Sync + 'static {
fn encode(value: &T, bytes: &mut Vec<u8>) -> Result<(), MessageError>;
fn decoding_memory(input: DecodeInput<'_>) -> Result<usize, MessageError>;
fn decode(input: DecodeInput<'_>) -> Result<T, MessageError>;
}
pub trait Encode<W>: Send + 'static {
fn write(&self, bytes: &mut Vec<u8>) -> Result<(), MessageError>;
}
impl EncodeSettings {
pub(super) fn validate(&self) -> Result<(), Status> {
if self.message_bytes.get() > u32::MAX as usize || self.buffer_bytes.get() > self.message_bytes.get() {
return Err(Status::invalid_argument("gRPC encoding limits exceed supported capacity"));
}
Ok(())
}
}
impl<T: Portable> Wire<T> for Transcoded {
fn encode(value: &T, bytes: &mut Vec<u8>) -> Result<(), MessageError> {
harmos_sdk::grpc::encode(value, bytes)
}
fn decoding_memory(input: DecodeInput<'_>) -> Result<usize, MessageError> {
harmos_sdk::grpc::decoding_memory::<T>(input)
}
fn decode(input: DecodeInput<'_>) -> Result<T, MessageError> {
harmos_sdk::grpc::decode::<T>(input)
}
}
impl<W: Wire<T>, T: Send + Sync + 'static> Encode<W> for crate::operations::Response<T> {
fn write(&self, bytes: &mut Vec<u8>) -> Result<(), MessageError> {
W::encode(self, bytes)
}
}
impl<W, I, R> Encode<W> for Event<StreamItem<I>, crate::operations::Response<R>>
where
W: Wire<I> + Wire<R>,
I: Send + Sync + 'static,
R: Send + Sync + 'static,
{
fn write(&self, bytes: &mut Vec<u8>) -> Result<(), MessageError> {
match self {
Self::Item(value) => delimited(1, bytes, |bytes| <W as Wire<I>>::encode(value, bytes)),
Self::Completion(value) => delimited(2, bytes, |bytes| <W as Wire<R>>::encode(value, bytes)),
}
}
}
impl<W: Wire<D>, D: MemorySize + Send + 'static, E: Encode<W>> Codec<W, D, E> {
pub fn server(self) -> tonic::server::Grpc<Self> {
let decode = self.decoder.message_limit();
let encode = self.encode.message_bytes.get();
tonic::server::Grpc::new(self).max_decoding_message_size(decode).max_encoding_message_size(encode)
}
pub fn new(decode: DecodeSettings, encode: EncodeSettings) -> Result<Self, Status> {
encode.validate()?;
Ok(Self { decoder: Decoder::new(decode)?, encode, response: PhantomData })
}
}
impl<W: Wire<D>, D: MemorySize + Send + 'static, E: Encode<W>> tonic::codec::Codec for Codec<W, D, E> {
type Encode = E;
type Decode = StreamItem<D>;
type Encoder = Encoder<W, E>;
type Decoder = Decoder<W, D>;
fn encoder(&mut self) -> Self::Encoder {
Encoder { settings: self.encode, scratch: Vec::new(), response: PhantomData }
}
fn decoder(&mut self) -> Self::Decoder {
self.decoder.fork()
}
}
impl<W, E: Encode<W>> Encoder<W, E> {
fn message(&mut self, value: &E) -> Result<&[u8], Status> {
self.scratch.clear();
value.write(&mut self.scratch).map_err(|error| Status::internal(error.to_string()))?;
if self.scratch.len() > self.settings.message_bytes.get() {
return Err(Status::resource_exhausted("gRPC encoded message exceeds wire ceiling"));
}
Ok(&self.scratch)
}
}
impl<W: Send + 'static, E: Encode<W>> tonic::codec::Encoder for Encoder<W, E> {
type Item = E;
type Error = Status;
fn encode(&mut self, item: E, destination: &mut EncodeBuf<'_>) -> Result<(), Status> {
destination.put_slice(self.message(&item)?);
Ok(())
}
fn buffer_settings(&self) -> BufferSettings {
BufferSettings::new(self.settings.buffer_bytes.get(), 1)
}
}