use std::borrow::Cow;
use varing::{decode_u32_varint, encode_u32_varint_to, encoded_u32_varint_len};
use super::WireType;
pub use tuple::TupleEncoder;
#[cfg(any(feature = "std", feature = "alloc"))]
mod bytes;
#[cfg(any(feature = "std", feature = "alloc"))]
mod nodecraft;
mod primitives;
#[cfg(any(feature = "std", feature = "alloc"))]
mod string;
mod tuple;
pub trait DataRef<'a, D>
where
D: Data + ?Sized,
Self: Copy + core::fmt::Debug + Send + Sync,
{
fn decode(buf: &'a [u8]) -> Result<(usize, Self), DecodeError>
where
Self: Sized;
fn decode_length_delimited(src: &'a [u8]) -> Result<(usize, Self), DecodeError>
where
Self: Sized,
{
if D::WIRE_TYPE != WireType::LengthDelimited {
return Self::decode(src);
}
let (mut offset, len) = decode_u32_varint(src)?;
let len = len as usize;
if len + offset > src.len() {
return Err(DecodeError::buffer_underflow());
}
let src = &src[offset..offset + len];
let (bytes_read, value) = Self::decode(src)?;
#[cfg(debug_assertions)]
super::debug_assert_read_eq::<Self>(bytes_read, len);
offset += bytes_read;
Ok((offset, value))
}
}
pub trait Data: core::fmt::Debug + Send + Sync {
const WIRE_TYPE: WireType = WireType::LengthDelimited;
type Ref<'a>: DataRef<'a, Self>;
fn from_ref(val: Self::Ref<'_>) -> Result<Self, DecodeError>
where
Self: Sized;
fn encoded_len(&self) -> usize;
fn encoded_len_with_length_delimited(&self) -> usize {
let len = self.encoded_len();
match Self::WIRE_TYPE {
WireType::LengthDelimited => encoded_u32_varint_len(len as u32) + len,
_ => len,
}
}
fn encode(&self, buf: &mut [u8]) -> Result<usize, EncodeError>;
#[cfg(any(feature = "std", feature = "alloc"))]
fn encode_to_vec(&self) -> Result<std::vec::Vec<u8>, EncodeError> {
let len = self.encoded_len();
let mut vec = std::vec![0; len];
self.encode(&mut vec).map(|_| vec)
}
#[cfg(any(feature = "std", feature = "alloc"))]
fn encode_to_bytes(&self) -> Result<::bytes::Bytes, EncodeError> {
self.encode_to_vec().map(Into::into)
}
fn encode_length_delimited(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
if Self::WIRE_TYPE != WireType::LengthDelimited {
return self.encode(buf);
}
let len = self.encoded_len();
if len > u32::MAX as usize {
return Err(EncodeError::TooLarge);
}
let mut offset = 0;
offset += encode_u32_varint_to(len as u32, buf)?;
offset += self.encode(&mut buf[offset..])?;
#[cfg(debug_assertions)]
super::debug_assert_write_eq::<Self>(offset, self.encoded_len_with_length_delimited());
Ok(offset)
}
#[cfg(any(feature = "std", feature = "alloc"))]
fn encode_length_delimited_to_vec(&self) -> Result<std::vec::Vec<u8>, EncodeError> {
let len = self.encoded_len_with_length_delimited();
let mut vec = std::vec![0; len];
self.encode_length_delimited(&mut vec).map(|_| vec)
}
#[cfg(any(feature = "std", feature = "alloc"))]
fn encode_length_delimited_to_bytes(&self) -> Result<::bytes::Bytes, EncodeError> {
self.encode_length_delimited_to_vec().map(Into::into)
}
fn decode(src: &[u8]) -> Result<(usize, Self), DecodeError>
where
Self: Sized,
{
<Self::Ref<'_> as DataRef<Self>>::decode(src)
.and_then(|(bytes_read, value)| Self::from_ref(value).map(|val| (bytes_read, val)))
}
fn decode_length_delimited(buf: &[u8]) -> Result<(usize, Self), DecodeError>
where
Self: Sized,
{
<Self::Ref<'_> as DataRef<Self>>::decode_length_delimited(buf)
.and_then(|(bytes_read, value)| Self::from_ref(value).map(|val| (bytes_read, val)))
}
}
#[derive(Debug, thiserror::Error)]
pub enum EncodeError {
#[error("insufficient buffer capacity, required: {required}, remaining: {remaining}")]
InsufficientBuffer {
required: usize,
remaining: usize,
},
#[error("encoded data is too large, the maximum allowed size is {MAX} bytes", MAX = u32::MAX)]
TooLarge,
#[error("{0}")]
Custom(Cow<'static, str>),
}
impl EncodeError {
#[inline]
pub const fn insufficient_buffer(required: usize, remaining: usize) -> Self {
Self::InsufficientBuffer {
required,
remaining,
}
}
pub fn custom<T>(value: T) -> Self
where
T: Into<Cow<'static, str>>,
{
Self::Custom(value.into())
}
pub fn update(mut self, required: usize, remaining: usize) -> Self {
match self {
Self::InsufficientBuffer {
required: ref mut r,
remaining: ref mut rem,
} => {
*r = required;
*rem = remaining;
self
}
_ => self,
}
}
}
impl From<varing::EncodeError> for EncodeError {
#[inline]
fn from(value: varing::EncodeError) -> Self {
match value {
varing::EncodeError::Underflow {
required,
remaining,
} => Self::InsufficientBuffer {
required,
remaining,
},
varing::EncodeError::Custom(e) => EncodeError::custom(e),
_ => EncodeError::custom("unknown encoding error"),
}
}
}
impl From<Cow<'static, str>> for EncodeError {
fn from(value: Cow<'static, str>) -> Self {
Self::Custom(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, derive_more::IsVariant)]
pub enum DecodeError {
#[error("buffer underflow")]
BufferUnderflow,
#[error("missing {field} in {ty}")]
MissingField {
ty: &'static str,
field: &'static str,
},
#[error("duplicate field {field} with tag {tag} in {ty}")]
DuplicateField {
ty: &'static str,
field: &'static str,
tag: u8,
},
#[error("unknown wire type value {value} with tag {tag} when decoding {ty}")]
UnknownWireType {
ty: &'static str,
value: u8,
tag: u8,
},
#[error("unknown tag {tag} when decoding {ty}")]
UnknownTag {
ty: &'static str,
tag: u8,
},
#[error("length-delimited overflow the maximum value of u32")]
LengthDelimitedOverflow,
#[error("{0}")]
Custom(Cow<'static, str>),
}
impl From<varing::DecodeError> for DecodeError {
#[inline]
fn from(e: varing::DecodeError) -> Self {
match e {
varing::DecodeError::Underflow => Self::BufferUnderflow,
varing::DecodeError::Overflow => Self::LengthDelimitedOverflow,
varing::DecodeError::Custom(e) => Self::custom(e),
_ => {
Self::custom("unknown decoding error")
}
}
}
}
impl DecodeError {
#[inline]
pub const fn buffer_underflow() -> Self {
Self::BufferUnderflow
}
#[inline]
pub const fn missing_field(ty: &'static str, field: &'static str) -> Self {
Self::MissingField { ty, field }
}
#[inline]
pub const fn duplicate_field(ty: &'static str, field: &'static str, tag: u8) -> Self {
Self::DuplicateField { ty, field, tag }
}
#[inline]
pub const fn unknown_wire_type(ty: &'static str, value: u8, tag: u8) -> Self {
Self::UnknownWireType { ty, value, tag }
}
#[inline]
pub const fn unknown_tag(ty: &'static str, tag: u8) -> Self {
Self::UnknownTag { ty, tag }
}
#[inline]
pub fn custom<T>(value: T) -> Self
where
T: Into<Cow<'static, str>>,
{
Self::Custom(value.into())
}
}