blob: b0c84d8e8a9ce5448efce49fbc86e97fac1e046b [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use super::*;
use anyhow::Context;
use byteorder::{BigEndian, ByteOrder, LittleEndian, WriteBytesExt};
use core::hash::Hash;
use std::collections::HashSet;
use std::convert::TryInto;
macro_rules! impl_try_array_unpack_sized(
($self:ty, $lifetime:lifetime) => {
fn try_array_unpack(iter: &mut std::slice::Iter<$lifetime, u8>) -> anyhow::Result<<$self>::Unpacked> {
let data: &[u8] = TryUnpackAs::<SpinelDataWlen>::try_unpack_as(iter)?;
Self::try_unpack_from_slice(data)
}
}
);
macro_rules! impl_try_array_owned_unpack_sized(
($self:ty) => {
fn try_array_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<<$self>::Unpacked> {
let data: &[u8] = TryUnpackAs::<SpinelDataWlen>::try_unpack_as(iter)?;
Self::try_owned_unpack_from_slice(data)
}
}
);
macro_rules! impl_try_pack_unpack_as_data(
(u8) => {
// We skip u8.
};
($self:ty) => {
impl<'a> TryUnpackAs<'a, [u8]> for $self {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
Self::try_unpack(iter)
}
}
impl<'a> TryUnpackAs<'a, SpinelDataWlen> for $self {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
// Get a reference to the buffer.
let buffer: &'a[u8] = TryUnpackAs::<SpinelDataWlen>::try_unpack_as(iter)?;
// Unpack using that buffer.
TryUnpackAs::<[u8]>::try_unpack_as(&mut buffer.iter())
}
}
impl TryPackAs<[u8]> for $self {
fn pack_as_len(&self) -> io::Result<usize> {
self.pack_len()
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
self.try_pack(buffer)
}
}
impl TryPackAs<SpinelDataWlen> for $self {
fn pack_as_len(&self) -> io::Result<usize> {
self.pack_len().map(|x|x+2)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
// Start with the length of the encoding
let mut len = TryPackAs::<[u8]>::pack_as_len(self)?;
// Encode the length of the buffer and add the
// length of that to our total length.
len += TryPackAs::<u16>::try_pack_as(&(len as u16), buffer)?;
// Encode the rest of the object into the buffer.
TryPackAs::<[u8]>::try_pack_as(self, buffer)?;
Ok(len)
}
}
};
($self:ty $(,$next:ty)*,) => {
impl_try_pack_unpack_as_data!($self $(,$next)*);
};
($self:ty $(,$next:ty)*) => {
impl_try_pack_unpack_as_data!($self);
impl_try_pack_unpack_as_data!($($next,)*);
};
);
/// Private convenience macro for defining the appropriate
/// traits for primitive types with fixed encoding lengths.
macro_rules! def_fixed_len(
($t:ty, $len:expr, |$pack_buf:ident, $pack_var:ident| $pack_block:expr, | $unpack_buf:ident | $unpack_block:expr) => {
def_fixed_len!($t, $len, $t, |$pack_buf, $pack_var|$pack_block, | $unpack_buf | $unpack_block);
};
($t:ty, $len:expr, $pack_as:ty, |$pack_buf:ident, $pack_var:ident| $pack_block:expr, | $unpack_buf:ident | $unpack_block:expr) => {
impl_try_pack_unpack_as_data!($t);
impl TryPackAs<$pack_as> for $t {
fn pack_as_len(&self) -> io::Result<usize> {
Ok(<$t>::FIXED_LEN)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
let pack = | $pack_buf: &mut T, $pack_var: $t | $pack_block;
//let pack: dyn Fn(&mut T, $t) -> io::Result<()> = $pack_block;
pack (buffer, *self).map(|_|<$t>::FIXED_LEN)
}
}
impl SpinelFixedLen for $t {
const FIXED_LEN: usize = $len;
}
impl TryPack for $t {
fn pack_len(&self) -> io::Result<usize> {
TryPackAs::<$pack_as>::pack_as_len(self)
}
fn try_pack<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<$pack_as>::try_pack_as(self, buffer)
}
}
impl<'a> TryUnpackAs<'a, $pack_as> for $t {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
let unpack_fn = | $unpack_buf: &[u8] | $unpack_block;
if iter.len() < <$t>::FIXED_LEN {
Err(UnpackingError::InvalidInternalLength)?
}
let result: Result<$t,UnpackingError> = unpack_fn(iter.as_slice());
*iter = iter.as_slice()[<$t>::FIXED_LEN..].iter();
Ok(result?)
}
}
impl_try_unpack_for_owned! {
impl TryOwnedUnpack for $t {
type Unpacked = Self;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
TryUnpackAs::<$pack_as>::try_unpack_as(iter)
}
}
}
};
);
def_fixed_len!(u8, 1, |b, v| b.write_u8(v), |buffer| Ok(buffer[0]));
def_fixed_len!(i8, 1, |b, v| b.write_i8(v), |buffer| Ok(buffer[0] as i8));
def_fixed_len!(u16, 2, |b, v| b.write_u16::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_u16(
buffer
)));
def_fixed_len!(i16, 2, |b, v| b.write_i16::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_i16(
buffer
)));
def_fixed_len!(u32, 4, |b, v| b.write_u32::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_u32(
buffer
)));
def_fixed_len!(i32, 4, |b, v| b.write_i32::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_i32(
buffer
)));
def_fixed_len!(u64, 8, |b, v| b.write_u64::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_u64(
buffer
)));
def_fixed_len!(i64, 8, |b, v| b.write_i64::<LittleEndian>(v), |buffer| Ok(LittleEndian::read_i64(
buffer
)));
def_fixed_len!(bool, 1, |b, v| b.write_u8(v as u8), |buffer| match buffer[0] {
0 => Ok(false),
1 => Ok(true),
_ => Err(UnpackingError::InvalidValue),
});
def_fixed_len!((), 0, |_b, _v| { Ok(()) }, |_b| Ok(()));
def_fixed_len!(std::net::Ipv6Addr, 16, |b, v| b.write_u128::<BigEndian>(v.into()), |b| Ok(
BigEndian::read_u128(b).into()
));
def_fixed_len!(EUI64, 8, |b, v| b.write_all((&v).into()), |b| Ok(EUI64([
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]
])));
def_fixed_len!(EUI48, 6, |b, v| b.write_all((&v).into()), |b| Ok(EUI48([
b[0], b[1], b[2], b[3], b[4], b[5]
])));
impl TryPack for str {
fn pack_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(self)
}
fn try_pack<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(self, buffer)
}
}
impl TryPack for &str {
fn pack_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(*self)
}
fn try_pack<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(*self, buffer)
}
}
impl TryPack for String {
fn pack_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(self.as_str())
}
fn try_pack<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(self.as_str(), buffer)
}
}
impl TryPackAs<str> for str {
fn pack_as_len(&self) -> io::Result<usize> {
Ok(self.as_bytes().len() + 1)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
let bytes = self.as_bytes();
let len = bytes.len() + 1;
if len > std::u16::MAX as usize {
Err(io::ErrorKind::InvalidInput.into())
} else if buffer.write(bytes)? != bytes.len() || buffer.write(&[0u8; 1])? != 1 {
Err(io::ErrorKind::Other.into())
} else {
Ok(len)
}
}
}
impl TryPackAs<str> for &str {
fn pack_as_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(*self)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(*self, buffer)
}
}
impl TryPackAs<str> for String {
fn pack_as_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(self.as_str())
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(self.as_str(), buffer)
}
}
impl TryPackAs<str> for [u8] {
fn pack_as_len(&self) -> io::Result<usize> {
Ok(self.len() + 1)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
let string = std::str::from_utf8(self)
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
TryPackAs::<str>::try_pack_as(string, buffer)
}
}
impl TryPackAs<str> for &[u8] {
fn pack_as_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(*self)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(*self, buffer)
}
}
impl TryPackAs<str> for Vec<u8> {
fn pack_as_len(&self) -> io::Result<usize> {
TryPackAs::<str>::pack_as_len(self.as_slice())
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> io::Result<usize> {
TryPackAs::<str>::try_pack_as(self.as_slice(), buffer)
}
}
impl TryPack for [u8] {
fn pack_len(&self) -> io::Result<usize> {
TryPackAs::<[u8]>::pack_as_len(self)
}
fn try_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
TryPackAs::<[u8]>::try_pack_as(self, buffer)
}
fn try_array_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
TryPackAs::<SpinelDataWlen>::try_pack_as(self, buffer)
}
}
impl<T: TryPack> TryPack for Vec<T> {
fn pack_len(&self) -> io::Result<usize> {
let mut len: usize = 0;
for iter in self.iter() {
len += iter.array_pack_len()?;
}
Ok(len)
}
fn try_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
let mut len: usize = 0;
// Write out the elements of the data
for iter in self.iter() {
len += iter.try_array_pack(buffer)?;
}
Ok(len)
}
fn array_pack_len(&self) -> io::Result<usize> {
self.pack_len().map(|len| len + 2)
}
fn try_array_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
let pack_len = self.pack_len()?;
// Write out the length of the data
let pack_len: u16 =
pack_len.try_into().map_err(|_| io::Error::from(io::ErrorKind::InvalidInput))?;
TryPackAs::<u16>::try_pack_as(&pack_len, buffer)?;
self.try_pack(buffer).map(|len| len + 2)
}
}
impl<T: TryPack> TryPack for HashSet<T> {
fn pack_len(&self) -> io::Result<usize> {
let mut len: usize = 0;
for iter in self.iter() {
len += iter.array_pack_len()?;
}
Ok(len)
}
fn try_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
let mut len: usize = 0;
// Write out the elements of the data
for iter in self.iter() {
len += iter.try_array_pack(buffer)?;
}
Ok(len)
}
fn array_pack_len(&self) -> io::Result<usize> {
self.pack_len().map(|len| len + 2)
}
fn try_array_pack<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
let pack_len = self.pack_len()?;
// Write out the length of the data
let pack_len: u16 =
pack_len.try_into().map_err(|_| io::Error::from(io::ErrorKind::InvalidInput))?;
TryPackAs::<u16>::try_pack_as(&pack_len, buffer)?;
self.try_pack(buffer).map(|len| len + 2)
}
}
impl TryPackAs<SpinelDataWlen> for [u8] {
fn pack_as_len(&self) -> std::io::Result<usize> {
Ok(self.len() + 2)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> std::io::Result<usize> {
let bytes = self;
let len = bytes.len() + 2;
if len > std::u16::MAX as usize {
Err(io::ErrorKind::InvalidInput.into())
} else {
buffer.write_u16::<LittleEndian>((len - 2) as u16)?;
buffer.write_all(bytes)?;
Ok(len)
}
}
}
impl TryPackAs<SpinelDataWlen> for &[u8] {
fn pack_as_len(&self) -> std::io::Result<usize> {
Ok(self.len() + 2)
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> std::io::Result<usize> {
let bytes = *self;
let len = bytes.len() + 2;
if len > std::u16::MAX as usize {
Err(io::ErrorKind::InvalidInput.into())
} else {
buffer.write_u16::<LittleEndian>((len - 2) as u16)?;
buffer.write_all(bytes)?;
Ok(len)
}
}
}
impl TryPackAs<[u8]> for [u8] {
fn pack_as_len(&self) -> std::io::Result<usize> {
Ok(self.len())
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> std::io::Result<usize> {
let bytes = self;
let len = bytes.len();
if len > std::u16::MAX as usize {
Err(io::ErrorKind::InvalidInput.into())
} else {
buffer.write_all(bytes).map(|_| len)
}
}
}
impl<'a> TryPackAs<[u8]> for &'a [u8] {
fn pack_as_len(&self) -> std::io::Result<usize> {
Ok(self.len())
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> std::io::Result<usize> {
let bytes = *self;
let len = bytes.len();
if len > std::u16::MAX as usize {
Err(io::ErrorKind::InvalidInput.into())
} else {
buffer.write_all(bytes).map(|_| len)
}
}
}
/// Borrowed unpack for EUI64
impl<'a> TryUnpack<'a> for &'a EUI64 {
type Unpacked = Self;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
if iter.len() < std::mem::size_of::<EUI64>() {
Err(UnpackingError::InvalidInternalLength)?
}
// Convert the iterator into a slice.
let ret = &iter.as_slice()[..std::mem::size_of::<EUI64>()];
// Move the iterator to the end.
*iter = ret[ret.len()..].iter();
Ok(ret.try_into().unwrap())
}
}
/// Borrowed unpack for EUI48
impl<'a> TryUnpack<'a> for &'a EUI48 {
type Unpacked = Self;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
if iter.len() < std::mem::size_of::<EUI48>() {
Err(UnpackingError::InvalidInternalLength)?
}
// Convert the iterator into a slice.
let ret = &iter.as_slice()[..std::mem::size_of::<EUI48>()];
// Move the iterator to the end.
*iter = ret[ret.len()..].iter();
Ok(ret.try_into().unwrap())
}
}
impl<'a> TryUnpack<'a> for &'a [u8] {
type Unpacked = Self;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
// Convert the iterator into a slice.
let ret = iter.as_slice();
// Move the iterator to the end.
*iter = ret[ret.len()..].iter();
Ok(ret)
}
impl_try_array_unpack_sized!(Self, 'a);
}
impl<'a> TryUnpackAs<'a, [u8]> for &'a [u8] {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
Self::try_unpack(iter)
}
}
impl<'a> TryUnpackAs<'a, SpinelDataWlen> for &'a [u8] {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
let len = u16::try_unpack(iter)? as usize;
let ret = iter.as_slice();
if ret.len() < len {
Err(UnpackingError::InvalidInternalLength)?
}
// Move the iterator to the end.
*iter = ret[len..].iter();
Ok(&ret[..len])
}
}
impl<'a> TryUnpack<'a> for &'a str {
type Unpacked = Self;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
TryUnpackAs::<str>::try_unpack_as(iter)
}
}
impl<'a> TryUnpackAs<'a, str> for &'a str {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
let mut split = iter.as_slice().splitn(2, |c| *c == 0);
let str_bytes: &[u8] = split.next().ok_or(UnpackingError::UnterminatedString)?.into();
*iter = split.next().ok_or(UnpackingError::UnterminatedString)?.iter();
std::str::from_utf8(str_bytes).context(UnpackingError::InvalidValue)
}
}
impl<'a> TryUnpackAs<'a, str> for String {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
<&str>::try_unpack(iter).map(ToString::to_string)
}
}
impl<'a> TryUnpackAs<'a, str> for &'a [u8] {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
<&str as TryUnpackAs<str>>::try_unpack_as(iter).map(str::as_bytes)
}
}
impl<'a> TryUnpackAs<'a, str> for Vec<u8> {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
<&[u8] as TryUnpackAs<str>>::try_unpack_as(iter).map(<[u8]>::to_vec)
}
}
impl_try_unpack_for_owned! {
impl TryOwnedUnpack for String {
type Unpacked = Self;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
<&str>::try_unpack(iter).map(ToString::to_string)
}
}
}
impl TryPackAs<SpinelUint> for u32 {
fn pack_as_len(&self) -> std::io::Result<usize> {
if *self < (1 << 7) {
Ok(1)
} else if *self < (1 << 14) {
Ok(2)
} else if *self < (1 << 21) {
Ok(3)
} else if *self < (1 << 28) {
Ok(4)
} else {
Ok(5)
}
}
fn try_pack_as<T: std::io::Write + ?Sized>(&self, buffer: &mut T) -> std::io::Result<usize> {
let len = TryPackAs::<SpinelUint>::pack_as_len(self)?;
let mut value = *self;
let mut inner_buffer = [0u8; 5];
for i in 0..(len - 1) {
inner_buffer[i] = ((value & 0x7F) | 0x80) as u8;
value = value >> 7;
}
inner_buffer[len - 1] = (value & 0x7F) as u8;
buffer.write_all(&inner_buffer[..len])?;
Ok(len)
}
}
impl<'a> TryUnpackAs<'a, SpinelUint> for u32 {
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
let mut len: usize = 0;
let mut value: u32 = 0;
let mut i = 0;
loop {
if len >= 5 {
return Err(UnpackingError::InvalidValue.into());
}
let byte = iter.next().ok_or(UnpackingError::InvalidInternalLength)?;
len += 1;
value |= ((byte & 0x7F) as u32) << i;
if byte & 0x80 != 0x80 {
break;
}
i += 7;
}
Ok(value)
}
}
impl_try_unpack_for_owned! {
impl TryOwnedUnpack for SpinelUint {
type Unpacked = u32;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
TryUnpackAs::<SpinelUint>::try_unpack_as(iter)
}
}
}
impl<T> TryOwnedUnpack for [T]
where
T: TryOwnedUnpack,
{
type Unpacked = Vec<T::Unpacked>;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
let mut ret: Self::Unpacked = Vec::with_capacity(iter.size_hint().0);
while iter.len() != 0 {
ret.push(T::try_array_owned_unpack(iter)?);
}
Ok(ret)
}
impl_try_array_owned_unpack_sized!(Self);
}
impl<T> TryOwnedUnpack for Vec<T>
where
T: TryOwnedUnpack,
{
type Unpacked = Vec<T::Unpacked>;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
let mut ret: Self::Unpacked = Vec::with_capacity(iter.size_hint().0);
while iter.len() != 0 {
ret.push(T::try_array_owned_unpack(iter)?);
}
Ok(ret)
}
impl_try_array_owned_unpack_sized!(Self);
}
impl<'a, T> TryUnpack<'a> for Vec<T>
where
T: TryUnpack<'a>,
{
type Unpacked = Vec<T::Unpacked>;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
let mut ret: Self::Unpacked = Vec::with_capacity(iter.size_hint().0);
while iter.len() != 0 {
ret.push(T::try_array_unpack(iter)?);
}
Ok(ret)
}
impl_try_array_unpack_sized!(Self, 'a);
}
impl<T> TryOwnedUnpack for HashSet<T>
where
T: TryOwnedUnpack,
T::Unpacked: Eq + Hash,
{
type Unpacked = HashSet<T::Unpacked>;
fn try_owned_unpack(iter: &mut std::slice::Iter<'_, u8>) -> anyhow::Result<Self::Unpacked> {
let mut ret: Self::Unpacked = Default::default();
while iter.len() != 0 {
ret.insert(T::try_array_owned_unpack(iter)?);
}
Ok(ret)
}
impl_try_array_owned_unpack_sized!(Self);
}
impl<'a, T> TryUnpack<'a> for HashSet<T>
where
T: TryUnpack<'a>,
T::Unpacked: Eq + Hash,
{
type Unpacked = HashSet<T::Unpacked>;
fn try_unpack(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self::Unpacked> {
let mut ret: Self::Unpacked = Default::default();
while iter.len() != 0 {
ret.insert(T::try_array_unpack(iter)?);
}
Ok(ret)
}
impl_try_array_unpack_sized!(Self, 'a);
}
impl<'a, T> TryUnpackAs<'a, [u8]> for Vec<T>
where
Self: TryUnpack<'a, Unpacked = Vec<T>>,
{
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
Self::try_unpack(iter)
}
}
impl<'a, T> TryUnpackAs<'a, SpinelDataWlen> for Vec<T>
where
Self: TryUnpackAs<'a, [u8]>,
{
fn try_unpack_as(iter: &mut std::slice::Iter<'a, u8>) -> anyhow::Result<Self> {
// Get a reference to the buffer.
let buffer: &'a [u8] = TryUnpackAs::<SpinelDataWlen>::try_unpack_as(iter)?;
// Unpack using that buffer.
TryUnpackAs::<[u8]>::try_unpack_as(&mut buffer.iter())
}
}
impl<T> TryPackAs<[u8]> for Vec<T>
where
Self: TryPack,
{
fn pack_as_len(&self) -> io::Result<usize> {
self.pack_len()
}
fn try_pack_as<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
self.try_pack(buffer)
}
}
impl<T> TryPackAs<SpinelDataWlen> for Vec<T>
where
Self: TryPackAs<[u8]>,
{
fn pack_as_len(&self) -> io::Result<usize> {
TryPackAs::<[u8]>::pack_as_len(self).map(|x| x + 2)
}
fn try_pack_as<B: std::io::Write + ?Sized>(&self, buffer: &mut B) -> io::Result<usize> {
// Start with the length of the encoding
let mut len = TryPackAs::<[u8]>::pack_as_len(self)?;
// Encode the length of the buffer and add the
// length of that to our total length.
len += TryPackAs::<u16>::try_pack_as(&(len as u16), buffer)?;
// Encode the rest of the object into the buffer.
TryPackAs::<[u8]>::try_pack_as(self, buffer)?;
Ok(len)
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
/// A verification that Spinel structs with
/// both `d` and `D` fields compile correctly.
#[allow(unused)]
#[spinel_packed("dD")]
#[derive(Debug, Hash, Clone, Eq, PartialEq)]
pub struct NetworkPacket<'a> {
pub packet: &'a [u8],
pub metadata: &'a [u8],
}
#[test]
fn test_uint_pack() {
let mut buffer = [0u8; 500];
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&0u32, &mut tmp_buffer).unwrap(), 1,);
assert_eq!(&tmp_buffer[0..1], &[0x00]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut tmp_buffer[0..1].iter()),
Ok(0u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&127u32, &mut tmp_buffer).unwrap(), 1,);
assert_eq!(&buffer[0..1], &[0x7F]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..1].iter()),
Ok(127u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&128u32, &mut tmp_buffer).unwrap(), 2,);
assert_eq!(&buffer[0..2], &[0x80, 0x01]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..2].iter()),
Ok(128u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&16383u32, &mut tmp_buffer).unwrap(), 2,);
assert_eq!(&buffer[0..2], &[0xFF, 0x7F]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..2].iter()),
Ok(16383u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&16384u32, &mut tmp_buffer).unwrap(), 3,);
assert_eq!(&buffer[0..3], &[0x80, 0x80, 0x01]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..3].iter()),
Ok(16384u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&2097151u32, &mut tmp_buffer).unwrap(), 3,);
assert_eq!(&buffer[0..3], &[0xFF, 0xFF, 0x7F]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..3].iter()),
Ok(2097151u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(TryPackAs::<SpinelUint>::try_pack_as(&2097152u32, &mut tmp_buffer).unwrap(), 4,);
assert_eq!(&buffer[0..4], &[0x80, 0x80, 0x80, 0x01]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..4].iter()),
Ok(2097152u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(
TryPackAs::<SpinelUint>::try_pack_as(&268435455u32, &mut tmp_buffer).unwrap(),
4,
);
assert_eq!(&buffer[0..4], &[0xFF, 0xFF, 0xFF, 0x7F]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..4].iter()),
Ok(268435455u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(
TryPackAs::<SpinelUint>::try_pack_as(&268435456u32, &mut tmp_buffer).unwrap(),
5,
);
assert_eq!(&buffer[0..5], &[0x80, 0x80, 0x80, 0x80, 0x01]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..5].iter()),
Ok(268435456u32)
);
let mut tmp_buffer = &mut buffer[..];
assert_eq!(
TryPackAs::<SpinelUint>::try_pack_as(&4294967295u32, &mut tmp_buffer).unwrap(),
5,
);
assert_eq!(&buffer[0..5], &[0xFF, 0xFF, 0xFF, 0xFF, 0x0F]);
assert_matches!(
TryUnpackAs::<SpinelUint>::try_unpack_as(&mut buffer[0..5].iter()),
Ok(4294967295u32)
);
}
#[test]
fn test_vec_owned_unpack() {
let buffer: &[u8] = &[0x34, 0x12, 0xcd, 0xab];
let out = Vec::<u16>::try_owned_unpack_from_slice(buffer).unwrap();
assert_eq!(out.as_slice(), &[0x1234, 0xabcd]);
}
#[test]
fn test_vec_unpack() {
let buffer: &[u8] = &[0x31, 0x32, 0x33, 0x00, 0x34, 0x35, 0x36, 0x00];
let out = Vec::<&str>::try_unpack_from_slice(buffer).unwrap();
assert_eq!(out.as_slice(), &["123", "456"]);
}
#[test]
fn test_string_as_vec() {
let buffer: &[u8] = &[0x31, 0x32, 0x33, 0x00];
let out = <&[u8] as TryUnpackAs<str>>::try_unpack_as_from_slice(buffer).unwrap();
assert_eq!(out, &[0x31, 0x32, 0x33]);
}
#[test]
fn test_hashset_owned_unpack() {
let buffer: &[u8] = &[0x34, 0x12, 0xcd, 0xab];
let out = HashSet::<u16>::try_owned_unpack_from_slice(buffer).unwrap();
assert!(out.contains(&0x1234));
assert!(out.contains(&0xabcd));
}
#[test]
fn test_hashset_unpack() {
let buffer: &[u8] = &[0x31, 0x32, 0x33, 0x00, 0x34, 0x35, 0x36, 0x00];
let out = HashSet::<&str>::try_unpack_from_slice(buffer).unwrap();
assert!(out.contains("123"));
assert!(out.contains("456"));
}
#[test]
fn test_u32_as_data_unpack() {
let buffer: &[u8] = &[0x67, 0x45, 0x23, 0x01, 0xfe, 0x0f, 0xdc, 0xba];
let out = Vec::<u32>::try_unpack_from_slice(buffer).unwrap();
assert_eq!(out, &[0x01234567, 0xbadc0ffe]);
}
#[test]
fn test_u32_as_data_unpack_wlen() {
let buffer: &[u8] = &[0x08, 0x00, 0x67, 0x45, 0x23, 0x01, 0xfe, 0x0f, 0xdc, 0xba];
let out = Vec::<u32>::try_array_unpack(&mut buffer.iter()).unwrap();
assert_eq!(out, &[0x01234567, 0xbadc0ffe]);
}
#[test]
fn test_u32_as_data_pack() {
let v: Vec<u32> = vec![0x01234567, 0xbadc0ffe];
let buffer: &[u8] = &[0x67, 0x45, 0x23, 0x01, 0xfe, 0x0f, 0xdc, 0xba];
let mut packed = Vec::with_capacity(v.pack_len().unwrap());
v.try_pack(&mut packed).unwrap();
assert_eq!(buffer, packed);
}
#[test]
fn test_u32_as_data_pack_wlen() {
let v: Vec<u32> = vec![0x01234567, 0xbadc0ffe];
let buffer: &[u8] = &[0x08, 0x00, 0x67, 0x45, 0x23, 0x01, 0xfe, 0x0f, 0xdc, 0xba];
let mut packed = Vec::with_capacity(v.array_pack_len().unwrap());
v.try_array_pack(&mut packed).unwrap();
assert_eq!(buffer, packed);
}
#[test]
fn test_u32_as_data_pack_struct() {
#[spinel_packed("d")]
#[derive(Debug, Hash, Clone, Eq, PartialEq)]
struct Blah {
v: Vec<u32>,
}
let v = Blah { v: vec![0x01234567, 0xbadc0ffe] };
let buffer: &[u8] = &[0x08, 0x00, 0x67, 0x45, 0x23, 0x01, 0xfe, 0x0f, 0xdc, 0xba];
let mut packed = Vec::with_capacity(v.pack_len().unwrap());
v.try_pack(&mut packed).unwrap();
assert_eq!(buffer, packed);
}
#[test]
fn test_container_pack_unpack() {
#[spinel_packed("6CLL")]
#[derive(Debug, Hash, Clone, Eq, PartialEq)]
pub struct AddressTableEntry {
pub addr: std::net::Ipv6Addr,
pub prefix_len: u8,
pub lifetime_a: u32,
pub lifetime_b: u32,
}
let buffer: &[u8] = &[
0x19, 0x0, 0xfd, 0xde, 0xad, 0x0, 0xbe, 0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0,
0xfc, 0x0, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0, 0xfd, 0xde,
0xad, 0x0, 0xbe, 0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x44, 0x0, 0x40, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0, 0xfd, 0xde, 0xad, 0x0, 0xbe, 0xef,
0x0, 0x0, 0xec, 0x2c, 0xb9, 0xec, 0xa5, 0x14, 0x96, 0xc, 0x40, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x19, 0x0, 0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28,
0x3f, 0xf, 0x66, 0x3e, 0xa7, 0x4d, 0x33, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
];
let out = Vec::<AddressTableEntry>::try_unpack_from_slice(buffer).unwrap();
assert!(out.contains(&AddressTableEntry {
addr: "fdde:ad00:beef::ff:fe00:4400".parse().unwrap(),
prefix_len: 64,
lifetime_a: 0xFFFFFFFF,
lifetime_b: 0xFFFFFFFF,
}));
assert!(out.contains(&AddressTableEntry {
addr: "fdde:ad00:beef::ff:fe00:fc00".parse().unwrap(),
prefix_len: 64,
lifetime_a: 0xFFFFFFFF,
lifetime_b: 0xFFFFFFFF,
}));
assert!(out.contains(&AddressTableEntry {
addr: "fdde:ad00:beef::ec2c:b9ec:a514:960c".parse().unwrap(),
prefix_len: 64,
lifetime_a: 0xFFFFFFFF,
lifetime_b: 0xFFFFFFFF,
}));
assert!(out.contains(&AddressTableEntry {
addr: "fe80::283f:f66:3ea7:4d33".parse().unwrap(),
prefix_len: 64,
lifetime_a: 0xFFFFFFFF,
lifetime_b: 0xFFFFFFFF,
}));
let buffer_pack = out.try_packed().expect("packing failed");
assert_eq!(buffer_pack.as_slice(), buffer);
}
}