mproto/
lib.rs

1#![feature(marker_trait_attr)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(all(not(feature = "std"), feature = "alloc"))]
5extern crate alloc;
6
7use core::{ops::Deref, pin::Pin};
8
9pub use boxed::BoxLazy;
10pub use decode_cursor::DecodeCursor;
11pub use encode_cursor::EncodeCursor;
12pub use list::{ListGen, ListLazy};
13
14mod boxed;
15mod copy_primitives;
16mod decode_cursor;
17mod encode_cursor;
18mod list;
19mod option;
20mod result;
21mod string;
22#[cfg(test)]
23mod tests;
24
25pub trait BaseLen {
26    const BASE_LEN: usize;
27}
28
29pub trait Encode: BaseLen {
30    fn scratch_len(&self) -> usize;
31
32    fn encode(&self, cursor: &mut EncodeCursor);
33}
34
35#[derive(Debug)]
36pub struct DecodeError;
37
38impl core::fmt::Display for DecodeError {
39    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40        write!(f, "failed to decode mproto value")
41    }
42}
43
44impl core::error::Error for DecodeError {}
45
46pub type DecodeResult<T> = Result<T, DecodeError>;
47
48pub trait Decode<'a>: BaseLen + Sized {
49    fn decode(cursor: &DecodeCursor<'a>) -> DecodeResult<Self>;
50}
51
52#[marker]
53pub trait Compatible<Other: ?Sized>: Encode {}
54
55impl<T: Encode> Compatible<T> for T {}
56
57pub trait Owned: Encode + for<'a> Decode<'a> + Clone + Send + Sync + 'static {
58    type Lazy<'a>: Lazy<'a, Owned = Self>;
59
60    fn lazy_to_owned(lazy: Self::Lazy<'_>) -> DecodeResult<Self>;
61}
62
63pub trait Lazy<'a>: Encode + Decode<'a> + Copy + Clone + PartialEq + core::fmt::Debug {
64    type Owned: Owned<Lazy<'a> = Self>;
65}
66
67pub fn encoded_len<T: Encode>(value: T) -> usize {
68    T::BASE_LEN + value.scratch_len()
69}
70
71pub fn encode_value<E: Encode>(v: E, mut buf: impl AsMut<[u8]>) -> usize {
72    let mut cursor = EncodeCursor::new::<E>(buf.as_mut());
73    v.encode(&mut cursor);
74    cursor.encoded_len()
75}
76
77#[cfg(any(feature = "std", feature = "alloc"))]
78pub fn encode_value_vec<E: Encode>(v: E) -> Vec<u8> {
79    let mut buf = vec![0u8; encoded_len(&v)];
80    let mut cursor = EncodeCursor::new::<E>(buf.as_mut());
81    v.encode(&mut cursor);
82    buf
83}
84
85pub fn decode_value<'a, D: Decode<'a>>(buf: &'a [u8]) -> DecodeResult<D> {
86    Decode::decode(&DecodeCursor::new(buf))
87}
88
89// TODO consider using Yoke, either directly in apps or wrapping it here.
90pub struct LazyBuf<T: Owned, B> {
91    buf: Pin<B>,
92    lazy: T::Lazy<'static>,
93}
94
95mod sealed {
96    // workaround for compiler limitation
97    // https://github.com/rust-lang/rust/issues/49601#issuecomment-1007884546
98    pub trait LazyBufMapFn<T, U>: FnOnce(T) -> U {}
99    impl<F, T, U> LazyBufMapFn<T, U> for F where F: FnOnce(T) -> U {}
100}
101
102impl<T: Owned, B: Deref<Target = [u8]> + core::marker::Unpin> LazyBuf<T, B> {
103    pub fn new(buf: B) -> Self {
104        let buf = Pin::new(buf);
105        let lazy: T::Lazy<'_> = decode_value(buf.as_ref().get_ref().as_ref()).unwrap();
106        // Erase lifetime of lazy value
107        let lazy = unsafe { core::mem::transmute(lazy) };
108        Self { buf, lazy }
109    }
110
111    pub fn get<'a>(&'a self) -> T::Lazy<'a> {
112        unsafe { core::mem::transmute(self.lazy.clone()) }
113    }
114
115    pub fn map<U: Owned, F>(self, f: F) -> LazyBuf<U, B>
116    where
117        F: for<'a> sealed::LazyBufMapFn<T::Lazy<'a>, U::Lazy<'a>>,
118    {
119        let lazy = f(self.lazy);
120        // Erase lifetime of lazy value
121        let lazy = unsafe { core::mem::transmute(lazy) };
122        LazyBuf {
123            buf: self.buf,
124            lazy,
125        }
126    }
127}
128
129impl<T, U: Compatible<T> + ?Sized> Compatible<T> for &U {}
130impl<T: ?Sized, U: Compatible<T>> Compatible<&T> for U {}
131
132impl<T: BaseLen + ?Sized> BaseLen for &T {
133    const BASE_LEN: usize = T::BASE_LEN;
134}
135
136impl<T: Encode + ?Sized> Encode for &T {
137    fn scratch_len(&self) -> usize {
138        T::scratch_len(self)
139    }
140
141    fn encode(&self, cursor: &mut EncodeCursor) {
142        T::encode(self, cursor);
143    }
144}
145
146impl<T: BaseLen + ?Sized> BaseLen for &mut T {
147    const BASE_LEN: usize = T::BASE_LEN;
148}
149
150impl<T: Encode + ?Sized> Encode for &mut T {
151    fn scratch_len(&self) -> usize {
152        T::scratch_len(self)
153    }
154
155    fn encode(&self, cursor: &mut EncodeCursor) {
156        T::encode(self, cursor);
157    }
158}
159
160pub const fn max(a: usize, b: usize) -> usize {
161    [a, b][(a < b) as usize]
162}