tonic-rpc 0.2.1

RPC library that uses native Rust types and is built on tonic.
Documentation
use std::{
    io::{Read, Write},
    marker::PhantomData,
};

use bytes::{buf::BufMut, Buf};
use serde::{Deserialize, Serialize};
use tonic::{codec, Status};

pub trait SerdeCodec {
    fn write<T, W>(item: T, w: W) -> Result<(), Status>
    where
        T: Serialize,
        W: Write;

    fn read<T, R>(r: R) -> Result<T, Status>
    where
        T: for<'de> Deserialize<'de>,
        R: Read;
}

#[derive(Clone, Copy)]
pub struct Encoder<C, T> {
    _pd: PhantomData<(C, T)>,
}

impl<C, T> codec::Encoder for Encoder<C, T>
where
    T: Serialize,
    C: SerdeCodec,
{
    type Item = T;
    type Error = Status;
    fn encode(
        &mut self,
        item: Self::Item,
        dst: &mut codec::EncodeBuf<'_>,
    ) -> Result<(), Self::Error> {
        C::write(item, dst.writer())
    }
}

#[derive(Clone, Copy)]
pub struct Decoder<C, T> {
    _pd: PhantomData<(C, T)>,
}

impl<C, T> codec::Decoder for Decoder<C, T>
where
    T: for<'de> Deserialize<'de>,
    C: SerdeCodec,
{
    type Item = T;
    type Error = Status;
    fn decode(
        &mut self,
        src: &mut codec::DecodeBuf<'_>,
    ) -> Result<Option<Self::Item>, Self::Error> {
        Ok(Some(C::read::<T, _>(src.reader())?))
    }
}

pub struct Codec<C, T, U> {
    _pd: PhantomData<(C, T, U)>,
}

impl<C, T, U> Default for Codec<C, T, U> {
    fn default() -> Self {
        Codec { _pd: PhantomData }
    }
}

impl<C, T, U> codec::Codec for Codec<C, T, U>
where
    C: SerdeCodec + Send + Sync + 'static,
    T: Serialize + Send + Sync + 'static,
    U: for<'de> Deserialize<'de> + Send + Sync + 'static,
{
    type Encode = T;
    type Decode = U;
    type Encoder = Encoder<C, T>;
    type Decoder = Decoder<C, U>;

    fn encoder(&mut self) -> Self::Encoder {
        Encoder { _pd: PhantomData }
    }

    fn decoder(&mut self) -> Self::Decoder {
        Decoder { _pd: PhantomData }
    }
}

#[cfg(feature = "bincode")]
#[cfg_attr(docsrs, doc(cfg(feature = "bincode")))]
pub struct BincodeSerdeCodec;
#[cfg(feature = "cbor")]
#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))]
pub struct CborSerdeCodec;
#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub struct JsonSerdeCodec;
#[cfg(feature = "messagepack")]
#[cfg_attr(docsrs, doc(cfg(feature = "messagepack")))]
pub struct MessagePackSerdeCodec;

#[cfg(feature = "bincode")]
#[cfg_attr(docsrs, doc(cfg(feature = "bincode")))]
impl SerdeCodec for BincodeSerdeCodec {
    fn write<T, W>(item: T, w: W) -> Result<(), Status>
    where
        T: Serialize,
        W: Write,
    {
        bincode::serialize_into(w, &item)
            .map_err(|bincode_err| Status::internal(format!("Error serializing {}", bincode_err)))
    }

    fn read<T, R>(r: R) -> Result<T, Status>
    where
        T: for<'de> Deserialize<'de>,
        R: Read,
    {
        bincode::deserialize_from(r)
            .map_err(|bincode_err| Status::internal(format!("Error deserializing {}", bincode_err)))
    }
}

#[cfg(feature = "cbor")]
#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))]
impl SerdeCodec for CborSerdeCodec {
    fn write<T, W>(item: T, w: W) -> Result<(), Status>
    where
        T: Serialize,
        W: Write,
    {
        serde_cbor::to_writer(w, &item)
            .map_err(|serde_err| Status::internal(format!("Error serializing {}", serde_err)))
    }

    fn read<T, R>(r: R) -> Result<T, Status>
    where
        T: for<'de> Deserialize<'de>,
        R: Read,
    {
        serde_cbor::from_reader(r)
            .map_err(|serde_err| Status::internal(format!("Error deserializing {}", serde_err)))
    }
}

#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
impl SerdeCodec for JsonSerdeCodec {
    fn write<T, W>(item: T, w: W) -> Result<(), Status>
    where
        T: Serialize,
        W: Write,
    {
        serde_json::to_writer(w, &item)
            .map_err(|serde_err| Status::internal(format!("Error serializing {}", serde_err)))
    }

    fn read<T, R>(r: R) -> Result<T, Status>
    where
        T: for<'de> Deserialize<'de>,
        R: Read,
    {
        serde_json::from_reader(r)
            .map_err(|serde_err| Status::internal(format!("Error deserializing {}", serde_err)))
    }
}

#[cfg(feature = "messagepack")]
#[cfg_attr(docsrs, doc(cfg(feature = "messagepack")))]
impl SerdeCodec for MessagePackSerdeCodec {
    fn write<T, W>(item: T, mut w: W) -> Result<(), Status>
    where
        T: Serialize,
        W: Write,
    {
        rmp_serde::encode::write(&mut w, &item).map_err(|message_pack_err| {
            Status::internal(format!("Error serializing {}", message_pack_err))
        })
    }

    fn read<T, R>(r: R) -> Result<T, Status>
    where
        T: for<'de> Deserialize<'de>,
        R: Read,
    {
        rmp_serde::from_read(r).map_err(|message_pack_err| {
            Status::internal(format!("Error deserializing {}", message_pack_err))
        })
    }
}

#[cfg(feature = "bincode")]
#[cfg_attr(docsrs, doc(cfg(feature = "bincode")))]
pub type BincodeCodec<T, U> = Codec<BincodeSerdeCodec, T, U>;
#[cfg(feature = "cbor")]
#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))]
pub type CborCodec<T, U> = Codec<CborSerdeCodec, T, U>;
#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub type JsonCodec<T, U> = Codec<JsonSerdeCodec, T, U>;
#[cfg(feature = "messagepack")]
#[cfg_attr(docsrs, doc(cfg(feature = "messagepack")))]
pub type MessagePackCodec<T, U> = Codec<MessagePackSerdeCodec, T, U>;