#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
use core::{ops::Deref, pin::Pin};
pub use boxed::BoxLazy;
pub use decode_cursor::DecodeCursor;
pub use encode_cursor::EncodeCursor;
pub use list::{ListGen, ListLazy};
mod boxed;
mod copy_primitives;
mod decode_cursor;
mod encode_cursor;
mod list;
mod option;
mod result;
mod string;
#[cfg(test)]
mod tests;
pub trait BaseLen {
const BASE_LEN: usize;
}
pub trait Encode: BaseLen {
fn scratch_len(&self) -> usize;
fn encode(&self, cursor: &mut EncodeCursor);
}
#[derive(Debug)]
pub struct DecodeError;
impl core::fmt::Display for DecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "failed to decode mproto value")
}
}
impl core::error::Error for DecodeError {}
pub type DecodeResult<T> = Result<T, DecodeError>;
pub trait Decode<'a>: BaseLen + Sized {
fn decode(cursor: &DecodeCursor<'a>) -> DecodeResult<Self>;
}
pub trait Compatible<Other: ?Sized>: Encode {}
pub trait Owned: Encode + for<'a> Decode<'a> + Compatible<Self> + Clone + Send + Sync + 'static {
type Lazy<'a>: Lazy<'a, Owned = Self>;
fn lazy_to_owned(lazy: Self::Lazy<'_>) -> DecodeResult<Self>;
}
pub trait Lazy<'a>: Encode + Decode<'a> + Copy + Clone + PartialEq + core::fmt::Debug {
type Owned: Owned<Lazy<'a> = Self>;
}
#[inline]
pub fn encoded_len<T: Encode>(value: T) -> usize {
T::BASE_LEN + value.scratch_len()
}
#[inline]
pub fn encode_value<E: Encode>(v: E, mut buf: impl AsMut<[u8]>) -> usize {
let mut cursor = EncodeCursor::new::<E>(buf.as_mut());
v.encode(&mut cursor);
cursor.encoded_len()
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn encode_value_vec<E: Encode>(v: E) -> Vec<u8> {
let mut buf = vec![0u8; encoded_len(&v)];
let mut cursor = EncodeCursor::new::<E>(buf.as_mut());
v.encode(&mut cursor);
buf
}
#[inline]
pub fn decode_value<'a, D: Decode<'a>>(buf: &'a [u8]) -> DecodeResult<D> {
Decode::decode(&DecodeCursor::new(buf))
}
pub struct LazyBuf<T: Owned, B> {
buf: Pin<B>,
lazy: T::Lazy<'static>,
}
mod sealed {
pub trait LazyBufMapFn<T, U>: FnOnce(T) -> U {}
impl<F, T, U> LazyBufMapFn<T, U> for F where F: FnOnce(T) -> U {}
}
impl<T: Owned, B: Deref<Target = [u8]> + core::marker::Unpin> LazyBuf<T, B> {
#[inline]
pub fn new(buf: B) -> Self {
let buf = Pin::new(buf);
let lazy: T::Lazy<'_> = decode_value(buf.as_ref().get_ref().as_ref()).unwrap();
let lazy = unsafe { core::mem::transmute(lazy) };
Self { buf, lazy }
}
#[inline]
pub fn get<'a>(&'a self) -> T::Lazy<'a> {
unsafe { core::mem::transmute(self.lazy.clone()) }
}
#[inline]
pub fn map<U: Owned, F>(self, f: F) -> LazyBuf<U, B>
where
F: for<'a> sealed::LazyBufMapFn<T::Lazy<'a>, U::Lazy<'a>>,
{
let lazy = f(self.lazy);
let lazy = unsafe { core::mem::transmute(lazy) };
LazyBuf {
buf: self.buf,
lazy,
}
}
}
impl<T, U: Compatible<T> + ?Sized> Compatible<T> for &U {}
impl<T: BaseLen + ?Sized> BaseLen for &T {
const BASE_LEN: usize = T::BASE_LEN;
}
impl<T: Encode + ?Sized> Encode for &T {
#[inline]
fn scratch_len(&self) -> usize {
T::scratch_len(self)
}
#[inline]
fn encode(&self, cursor: &mut EncodeCursor) {
T::encode(self, cursor);
}
}
impl<T: BaseLen + ?Sized> BaseLen for &mut T {
const BASE_LEN: usize = T::BASE_LEN;
}
impl<T: Encode + ?Sized> Encode for &mut T {
#[inline]
fn scratch_len(&self) -> usize {
T::scratch_len(self)
}
#[inline]
fn encode(&self, cursor: &mut EncodeCursor) {
T::encode(self, cursor);
}
}
pub const fn max(a: usize, b: usize) -> usize {
[a, b][(a < b) as usize]
}