use crate::{header::Header, Decoder, Encoder, Error, Length, Result, Tag, TaggedSlice};
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "alloc")]
use {alloc::vec::Vec, core::iter};
#[cfg(any(feature = "heapless", feature = "alloc"))]
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(&self, buf: &mut heapless::VecView<u8>) -> 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 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 super::{Container, Tagged};
use crate::{Decodable, Encodable, Error, Result, Tag, TagLike, TaggedSlice, TaggedValue};
use core::convert::TryFrom;
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,
{
}
#[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);
}
#[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());
}
}