use crate::{CborLen, Decode, Encode};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct With<'a, T> {
value: T,
bytes: &'a [u8],
}
impl<T> AsRef<T> for With<'_, T> {
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T> AsRef<[u8]> for With<'_, T> {
fn as_ref(&self) -> &[u8] {
self.bytes
}
}
impl<'a, T> From<(T, &'a [u8])> for With<'a, T> {
fn from((value, bytes): (T, &'a [u8])) -> Self {
With { value, bytes }
}
}
impl<'a, T> From<With<'a, T>> for (T, &'a [u8]) {
fn from(With { value, bytes }: With<'a, T>) -> Self {
(value, bytes)
}
}
impl<T> Encode for With<'_, T>
where
T: Encode,
{
fn encode<W: embedded_io::Write>(&self, e: &mut crate::Encoder<W>) -> Result<(), W::Error> {
e.0.write_all(self.bytes)
}
}
impl<'a, T> Decode<'a> for With<'a, T>
where
T: Decode<'a>,
{
type Error = T::Error;
fn decode(d: &mut crate::Decoder<'a>) -> Result<Self, Self::Error> {
let bytes = d.0;
let value = T::decode(d)?;
let offset = d.0.as_ptr() as usize - bytes.as_ptr() as usize;
Ok(With {
value,
bytes: &bytes[..offset],
})
}
}
impl<T> CborLen for With<'_, T>
where
T: CborLen,
{
fn cbor_len(&self) -> usize {
self.bytes.len()
}
}
pub struct Lazy<B, T> {
pub bytes: B,
pub(crate) _phantom: core::marker::PhantomData<T>,
}
impl<B, T> Lazy<B, T> {
pub fn decode<'a>(&'a self) -> Result<T, T::Error>
where
B: AsRef<[u8]>,
T: Decode<'a>,
{
T::decode(&mut crate::Decoder(self.bytes.as_ref()))
}
}
impl<B, T> From<B> for Lazy<B, T> {
fn from(bytes: B) -> Self {
Self {
bytes,
_phantom: core::marker::PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use super::{Lazy, With};
use crate::{Decode, Decoder};
use alloc::{string::String, vec::Vec};
const HELLO_CBOR: &[u8] = &[0x65, b'h', b'e', b'l', b'l', b'o', 0x00];
#[test]
fn borrow() {
let with = With::<&str>::decode(&mut Decoder(HELLO_CBOR)).unwrap();
let encoded = <With<'_, &str> as AsRef<[u8]>>::as_ref(&with);
let lazy_slice = Lazy::<&[u8], &str>::from(encoded);
assert_eq!(lazy_slice.decode().unwrap(), "hello");
}
#[test]
#[cfg(feature = "alloc")]
fn owned() {
let with = With::<String>::decode(&mut Decoder(HELLO_CBOR)).unwrap();
let encoded = <With<'_, String> as AsRef<[u8]>>::as_ref(&with);
let lazy_box = Lazy::<Box<[u8]>, String>::from(encoded.to_vec().into_boxed_slice());
assert_eq!(lazy_box.decode().unwrap(), "hello");
let lazy_vec = Lazy::<Vec<u8>, String>::from(encoded.to_vec());
assert_eq!(lazy_vec.decode().unwrap(), "hello");
}
}