mod proto;
mod json;
mod procedure;
#[cfg(feature = "arrow")]
mod arrow;
pub use json::JsonCodec;
pub use proto::ProtoCodec;
pub use procedure::{CodecSet, ProcedureCodecs};
#[cfg(feature = "arrow")]
pub use arrow::ArrowCodec;
use std::error::Error as StdError;
use bytes::Bytes;
use foundation_errstacks::ErrorTrace;
use crate::shared::error::{Code, ConnectError};
pub trait Codec: Send + Sync + 'static {
fn name(&self) -> &str;
fn is_binary(&self) -> bool;
}
pub trait CodecFor<M>: Codec {
fn marshal(&self, message: &M) -> Result<Bytes, CodecError>;
fn unmarshal(&self, data: Bytes) -> Result<M, CodecError>;
fn marshal_stable(&self, message: &M) -> Result<Bytes, CodecError>;
fn marshal_append(&self, buf: &mut Vec<u8>, message: &M) -> Result<(), CodecError>;
}
#[derive(Debug)]
pub enum CodecError {
Encode {
codec: &'static str,
message: String,
},
Decode {
codec: &'static str,
message: String,
},
ZeroLength {
codec: &'static str,
},
}
impl CodecError {
fn encode(codec: &'static str, message: impl Into<String>) -> Self {
CodecError::Encode {
codec,
message: message.into(),
}
}
fn decode(codec: &'static str, message: impl Into<String>) -> Self {
CodecError::Decode {
codec,
message: message.into(),
}
}
fn code(&self) -> Code {
match self {
CodecError::Encode { .. } => Code::Internal,
CodecError::Decode { .. } | CodecError::ZeroLength { .. } => Code::InvalidArgument,
}
}
fn to_connect_error(&self) -> ConnectError {
ConnectError::new(self.code(), self.to_string())
}
}
impl core::fmt::Display for CodecError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
CodecError::Encode { codec, message } => {
write!(f, "{codec} codec: encode failed: {message}")
}
CodecError::Decode { codec, message } => {
write!(f, "{codec} codec: decode failed: {message}")
}
CodecError::ZeroLength { codec } => {
write!(f, "{codec} codec: zero-length payload is not valid")
}
}
}
}
impl StdError for CodecError {}
impl From<CodecError> for ConnectError {
fn from(err: CodecError) -> Self {
err.to_connect_error()
}
}
impl From<CodecError> for ErrorTrace<ConnectError> {
fn from(err: CodecError) -> Self {
let connect = err.to_connect_error();
ErrorTrace::new(err).change_context(connect)
}
}