use core::borrow::Borrow;
use alloc::{
collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
vec::Vec,
};
use bytes::BufMut;
use crate::{format::Format, Packable};
pub fn pack_array_len<T>(buf: &mut T, len: usize) -> usize
where
T: BufMut,
{
if len <= 15 {
buf.put_u8(((len & 0x0f) as u8) | 0x90);
1
} else if len <= u16::MAX as usize {
let mut s = [0u8; 3];
s[0] = Format::ARRAY16;
s[1..].copy_from_slice(&(len as u16).to_be_bytes());
buf.put_slice(&s);
3
} else if len <= u32::MAX as usize {
let mut s = [0u8; 5];
s[0] = Format::ARRAY32;
s[1..].copy_from_slice(&(len as u32).to_be_bytes());
buf.put_slice(&s);
5
} else {
#[cfg(feature = "strict")]
panic!("strict serialization enabled; the buffer is too large");
#[allow(unreachable_code)]
return 0;
}
}
#[allow(unreachable_code)]
pub fn pack_array_slice<T, V>(buf: &mut T, items: &[V]) -> usize
where
T: BufMut,
V: Packable,
{
let len = items.len();
let mut sum = pack_array_len(buf, len);
for v in items {
sum += v.pack(buf);
}
sum
}
#[allow(unreachable_code)]
pub fn pack_array<T, A, I, V>(buf: &mut T, iter: A) -> usize
where
T: BufMut,
A: IntoIterator<IntoIter = I>,
I: Iterator<Item = V> + ExactSizeIterator,
V: Packable,
{
let values = iter.into_iter();
let len = values.len();
let n = pack_array_len(buf, len);
n + values.map(|v| v.pack(buf)).sum::<usize>()
}
pub fn pack_map_len<T>(buf: &mut T, len: usize) -> usize
where
T: BufMut,
{
if len <= 15 {
buf.put_u8(((len & 0x0f) as u8) | 0x80);
1
} else if len <= u16::MAX as usize {
let mut s = [0u8; 3];
s[0] = Format::MAP16;
s[1..].copy_from_slice(&(len as u16).to_be_bytes());
buf.put_slice(&s);
3
} else if len <= u32::MAX as usize {
let mut s = [0u8; 5];
s[0] = Format::MAP32;
s[1..].copy_from_slice(&(len as u32).to_be_bytes());
buf.put_slice(&s);
5
} else {
#[cfg(feature = "strict")]
panic!("strict serialization enabled; the buffer is too large");
#[allow(unreachable_code)]
return 0;
}
}
#[allow(unreachable_code)]
pub fn pack_map<T, A, I, B, K, V>(buf: &mut T, iter: A) -> usize
where
T: BufMut,
A: IntoIterator<IntoIter = I>,
B: Borrow<(K, V)>,
I: Iterator<Item = B> + ExactSizeIterator,
K: Packable,
V: Packable,
{
let map = iter.into_iter();
let len = map.len();
let n = pack_map_len(buf, len);
n + map
.map(|b| {
let (k, v) = b.borrow();
k.pack(buf) + v.pack(buf)
})
.sum::<usize>()
}
impl<X> Packable for [X]
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array_slice(buf, self)
}
}
impl<X> Packable for BTreeSet<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array(buf, self)
}
}
impl<X> Packable for BinaryHeap<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array(buf, self)
}
}
impl<X> Packable for LinkedList<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array(buf, self)
}
}
impl<X> Packable for Vec<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array_slice(buf, self.as_slice())
}
}
impl<X> Packable for VecDeque<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array(buf, self)
}
}
impl<K, V> Packable for BTreeMap<K, V>
where
K: Packable,
V: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_map(buf, self)
}
}
#[cfg(feature = "std")]
mod std {
use super::*;
use ::std::collections::{HashMap, HashSet};
impl<X> Packable for HashSet<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_array(buf, self)
}
}
impl<K, V> Packable for HashMap<K, V>
where
K: Packable,
V: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: BufMut,
{
pack_map(buf, self)
}
}
}