use core::convert::{TryFrom, TryInto};
use crate::{Decoder, Encoder, Error, header::Header, Length, Result, Tag, TaggedSlice, TaggedValue, TagLike};
#[cfg(feature = "alloc")]
use {
alloc::vec::Vec,
core::iter,
crate::ErrorKind,
};
#[cfg(feature = "heapless")]
use crate::ErrorKind;
pub trait Decodable<'a>: Sized {
fn decode(decoder: &mut Decoder<'a>) -> Result<Self>;
fn from_bytes(bytes: &'a [u8]) -> Result<Self> {
let mut decoder = Decoder::new(bytes);
let result = Self::decode(&mut decoder)?;
decoder.finish(result)
}
}
impl<'a, X> Decodable<'a> for X
where
X: TryFrom<TaggedSlice<'a>, Error = Error>,
{
fn decode(decoder: &mut Decoder<'a>) -> Result<Self> {
TaggedSlice::decode(decoder)
.and_then(Self::try_from)
.or_else(|e| decoder.error(e.kind()))
}
}
impl<'a, T> Decodable<'a> for Option<T>
where
T: Decodable<'a> + Tagged,
{
fn decode(decoder: &mut Decoder<'a>) -> Result<Option<T>> {
if let Some(byte) = decoder.peek() {
debug_now!("comparing {} against {} interpreted as {}", &T::tag(), byte, Tag::try_from(byte)?);
if T::tag() == Tag::try_from(byte)? {
return T::decode(decoder).map(Some);
}
}
Ok(None)
}
}
pub trait Encodable {
fn encoded_length(&self) -> Result<Length>;
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()>;
fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
let mut encoder = Encoder::new(buf);
self.encode(&mut encoder)?;
encoder.finish()
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
let expected_len = self.encoded_length()?.to_usize();
let current_len = buf.len();
buf.reserve(expected_len);
buf.extend(iter::repeat(0).take(expected_len));
let mut encoder = Encoder::new(&mut buf[current_len..]);
self.encode(&mut encoder)?;
let actual_len = encoder.finish()?.len();
if expected_len != actual_len {
return Err(ErrorKind::Underlength {
expected: expected_len.try_into()?,
actual: actual_len.try_into()?,
}
.into());
}
actual_len.try_into()
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
self.encode_to_vec(&mut buf)?;
Ok(buf)
}
}
#[cfg(feature = "heapless")]
#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
pub trait EncodableHeapless: Encodable {
fn encode_to_heapless_vec<const N: usize>(&self, buf: &mut heapless::Vec<u8, N>) -> Result<Length> {
let expected_len = self.encoded_length()?.to_usize();
let current_len = buf.len();
buf.resize_default(current_len + expected_len).map_err(|_| Error::from(ErrorKind::Overlength))?;
let mut encoder = Encoder::new(&mut buf[current_len..]);
self.encode(&mut encoder)?;
let actual_len = encoder.finish()?.len();
if expected_len != actual_len {
return Err(ErrorKind::Underlength {
expected: expected_len.try_into()?,
actual: actual_len.try_into()?,
}
.into());
}
actual_len.try_into()
}
fn to_heapless_vec<const N: usize>(&self) -> Result<heapless::Vec<u8, N>> {
let mut buf = heapless::Vec::new();
self.encode_to_heapless_vec(&mut buf)?;
Ok(buf)
}
}
#[cfg(feature = "heapless")]
impl<X> EncodableHeapless for X where X: Encodable {}
pub(crate) trait Taggable<T: TagLike>: Sized {
fn tagged(&self, tag: T) -> TaggedValue<&Self, T> {
TaggedValue::new(tag, self)
}
}
impl<T, X> Taggable<T> for X where X: Sized, T: TagLike {}
pub trait Tagged {
fn tag() -> Tag;
}
pub trait Container {
fn fields<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&[&dyn Encodable]) -> Result<T>;
}
impl<TaggedContainer> Encodable for TaggedContainer
where
TaggedContainer: Tagged + Container
{
fn encoded_length(&self) -> Result<Length> {
#[allow(clippy::redundant_closure)]
let value_length = self.fields(|encodables| Length::try_from(encodables))?;
Header::new(Self::tag(), value_length)?.encoded_length() + value_length
}
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
self.fields(|fields| encoder.encode_tagged_collection(Self::tag(), fields))
}
}
impl Encodable for &[u8] {
fn encoded_length(&self) -> Result<Length> {
self.len().try_into()
}
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
encoder.bytes(self)
}
}
impl<T> Encodable for Option<T>
where
T: Encodable
{
fn encoded_length(&self) -> Result<Length> {
match self {
Some(t) => t.encoded_length(),
None => Ok(Length::zero()),
}
}
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
match self {
Some(t) => t.encode(encoder),
None => Ok(())
}
}
}
macro_rules! impl_array {
($($N:literal),*) => {
$(
impl Encodable for [u8; $N] {
fn encoded_length(&self) -> Result<Length> {
Ok(($N as u8).into())
}
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
encoder.bytes(self.as_ref())
}
}
impl Decodable<'_> for [u8; $N] {
fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
use core::convert::TryInto;
let bytes: &[u8] = decoder.bytes($N as u8)?;
Ok(bytes.try_into().unwrap())
}
}
)*
}
}
impl_array!(
0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32
);
#[cfg(test)]
mod tests {
use core::convert::TryFrom;
use crate::{Decodable, Encodable, Error, Result, Tag, TaggedSlice, TagLike};
use super::{Taggable, Tagged, Container};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct S {
x: [u8; 2],
y: [u8; 3],
z: [u8; 4],
}
impl<'a> TryFrom<TaggedSlice<'a>> for S {
type Error = Error;
fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<S> {
tagged_slice.tag().assert_eq(Tag::try_from(0x0A).unwrap())?;
tagged_slice.decode_nested(|decoder| {
let x = decoder.decode_tagged_value(Tag::try_from(0x01).unwrap())?;
let y = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
let z = decoder.decode_tagged_value(Tag::try_from(0x03).unwrap())?;
Ok(Self { x, y, z })
})
}
}
impl Tagged for S {
fn tag() -> Tag {
Tag::try_from(0x0A).unwrap()
}
}
impl Container for S {
fn fields<F, T>(&self, field_encoder: F) -> Result<T>
where
F: FnOnce(&[&dyn Encodable]) -> Result<T>,
{
field_encoder(&[
&(Tag::try_from(0x01).unwrap().with_value(&self.x.as_ref())),
&self.y.as_ref().tagged(Tag::try_from(0x02).unwrap()),
&self.z.as_ref().tagged(Tag::try_from(0x03).unwrap()),
])
}
}
#[test]
fn reconstruct() {
let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
let mut buf = [0u8; 1024];
let encoded = s.encode_to_slice(&mut buf).unwrap();
assert_eq!(encoded,
&[0x0A, 15,
0x01, 2, 1, 2,
0x02, 3, 3, 4, 5,
0x03, 4, 6, 7, 8, 9,
],
);
let s2 = S::from_bytes(encoded).unwrap();
assert_eq!(s, s2);
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct T {
s: S,
t: [u8; 3],
}
impl<'a> TryFrom<TaggedSlice<'a>> for T {
type Error = Error;
fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<Self> {
tagged_slice.tag().assert_eq(Tag::try_from(0x0B).unwrap())?;
tagged_slice.decode_nested(|decoder| {
let s = decoder.decode_tagged_value(Tag::try_from(0x01).unwrap())?;
let t = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
Ok(Self { s, t })
})
}
}
impl Tagged for T {
fn tag() -> Tag {
Tag::try_from(0x0B).unwrap()
}
}
impl Container for T {
fn fields<F, Z>(&self, field_encoder: F) -> Result<Z>
where
F: FnOnce(&[&dyn Encodable]) -> Result<Z>,
{
field_encoder(&[
&self.s.tagged(Tag::try_from(0x1).unwrap()),
&self.t.as_ref().tagged(Tag::try_from(0x2).unwrap()),
])
}
}
#[test]
fn nesty() {
let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
let t = T { s, t: [0xA, 0xB, 0xC] };
let mut buf = [0u8; 1024];
let encoded = t.encode_to_slice(&mut buf).unwrap();
assert_eq!(encoded,
&[0x0B, 24,
0x1, 17,
0x0A, 15,
0x01, 2, 1, 2,
0x02, 3, 3, 4, 5,
0x03, 4, 6, 7, 8, 9,
0x2, 3,
0xA, 0xB, 0xC
],
);
let t2 = T::from_bytes(encoded).unwrap();
assert_eq!(t, t2);
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct T2 {
s: S,
t: [u8; 3],
}
impl<'a> TryFrom<TaggedSlice<'a>> for T2 {
type Error = Error;
fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<Self> {
tagged_slice.tag().assert_eq(Tag::try_from(0x0C).unwrap())?;
tagged_slice.decode_nested(|decoder| {
let s = decoder.decode()?;
let t = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
Ok(Self { s, t })
})
}
}
impl Tagged for T2 {
fn tag() -> Tag {
Tag::try_from(0x0C).unwrap()
}
}
impl Container for T2 {
fn fields<F, Z>(&self, field_encoder: F) -> Result<Z>
where
F: FnOnce(&[&dyn Encodable]) -> Result<Z>,
{
field_encoder(&[
&self.s,
&self.t.as_ref().tagged(Tag::try_from(0x2).unwrap()),
])
}
}
#[test]
fn nesty2() {
let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
let t = T2 { s, t: [0xA, 0xB, 0xC] };
let mut buf = [0u8; 1024];
let encoded = t.encode_to_slice(&mut buf).unwrap();
assert_eq!(encoded,
&[0x0C, 22,
0x0A, 15,
0x01, 2, 1, 2,
0x02, 3, 3, 4, 5,
0x03, 4, 6, 7, 8, 9,
0x2, 3,
0xA, 0xB, 0xC
],
);
let t2 = T2::from_bytes(encoded).unwrap();
assert_eq!(t, t2);
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct T3 {
s: S,
t: [u8; 3],
}
#[test]
fn derive_option() {
let mut buf = [0u8; 1024];
let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
let encoded = s.encode_to_slice(&mut buf).unwrap();
let mut decoder = crate::Decoder::new(&encoded);
let s: Option<S> = decoder.decode().unwrap();
assert!(s.is_some());
let empty = [0u8; 0];
let mut decoder = crate::Decoder::new(&empty);
let s: Option<S> = decoder.decode().unwrap();
assert!(s.is_none());
}
}