use crate::{asn1::sequence, Any, Decoder, Encoder, Error, Length, Result, Tag};
use core::convert::TryFrom;
#[cfg(feature = "alloc")]
use {
crate::ErrorKind,
alloc::vec::Vec,
core::{convert::TryInto, iter},
};
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, T> Decodable<'a> for T
where
T: TryFrom<Any<'a>, Error = Error>,
{
fn decode(decoder: &mut Decoder<'a>) -> Result<T> {
Any::decode(decoder)
.and_then(Self::try_from)
.or_else(|e| decoder.error(e.kind()))
}
}
pub trait Encodable {
fn encoded_len(&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)?;
Ok(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_len()?.to_usize();
buf.reserve(expected_len);
buf.extend(iter::repeat(0).take(expected_len));
let mut encoder = Encoder::new(buf);
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)
}
}
pub trait Tagged {
const TAG: Tag;
}
pub trait Message<'a>: Decodable<'a> {
fn fields<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&[&dyn Encodable]) -> Result<T>;
}
impl<'a, M> Encodable for M
where
M: Message<'a>,
{
fn encoded_len(&self) -> Result<Length> {
self.fields(sequence::encoded_len)
}
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
self.fields(|fields| encoder.sequence(fields))
}
}
impl<'a, M> Tagged for M
where
M: Message<'a>,
{
const TAG: Tag = Tag::Sequence;
}