use std::collections::{BTreeMap, HashMap};
use std::hash::{BuildHasher, Hash};
use tokio_dbus::{Alignment, Body, ObjectPath, ObjectPathBuf, Signature, SignatureBuf};
use crate::Result;
pub trait Decode: Sized {
const ALIGNMENT: Alignment;
fn decode(body: &mut Body<'_>) -> Result<Self>;
}
macro_rules! decode_frame {
($($ty:ty, $alignment:ident),* $(,)?) => {
$(
impl Decode for $ty {
const ALIGNMENT: Alignment = Alignment::$alignment;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
Ok(body.load::<$ty>()?)
}
}
)*
}
}
decode_frame! {
u8, BYTE,
i16, U16,
u16, U16,
i32, U32,
u32, U32,
i64, U64,
u64, U64,
f64, U64,
}
impl Decode for bool {
const ALIGNMENT: Alignment = Alignment::U32;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
Ok(body.load_bool()?)
}
}
impl Decode for String {
const ALIGNMENT: Alignment = Alignment::U32;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
Ok(body.read::<str>()?.to_owned())
}
}
impl Decode for ObjectPathBuf {
const ALIGNMENT: Alignment = Alignment::U32;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
Ok(body.read::<ObjectPath>()?.to_owned())
}
}
impl Decode for SignatureBuf {
const ALIGNMENT: Alignment = Alignment::BYTE;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
Ok(body.read::<Signature>()?.to_owned())
}
}
impl<T> Decode for Vec<T>
where
T: Decode,
{
const ALIGNMENT: Alignment = Alignment::U32;
fn decode(body: &mut Body<'_>) -> Result<Self> {
let mut array = body.load_raw_array(T::ALIGNMENT)?;
let mut out = Vec::new();
while !array.is_empty() {
out.push(T::decode(&mut array)?);
}
Ok(out)
}
}
fn decode_entries<K, V, O>(body: &mut Body<'_>, mut insert: impl FnMut(&mut O, K, V)) -> Result<O>
where
K: Decode,
V: Decode,
O: Default,
{
let mut array = body.load_raw_array(Alignment::U64)?;
let mut out = O::default();
while !array.is_empty() {
array.align_to(Alignment::U64)?;
let key = K::decode(&mut array)?;
let value = V::decode(&mut array)?;
insert(&mut out, key, value);
}
Ok(out)
}
impl<K, V, S> Decode for HashMap<K, V, S>
where
K: Decode + Eq + Hash,
V: Decode,
S: Default + BuildHasher,
{
const ALIGNMENT: Alignment = Alignment::U32;
fn decode(body: &mut Body<'_>) -> Result<Self> {
decode_entries(body, |out: &mut Self, key, value| {
out.insert(key, value);
})
}
}
impl<K, V> Decode for BTreeMap<K, V>
where
K: Decode + Ord,
V: Decode,
{
const ALIGNMENT: Alignment = Alignment::U32;
fn decode(body: &mut Body<'_>) -> Result<Self> {
decode_entries(body, |out: &mut Self, key, value| {
out.insert(key, value);
})
}
}
macro_rules! decode_tuple {
($($ty:ident),*) => {
impl<$($ty,)*> Decode for ($($ty,)*)
where
$($ty: Decode,)*
{
const ALIGNMENT: Alignment = Alignment::U64;
#[inline]
fn decode(body: &mut Body<'_>) -> Result<Self> {
body.align_to(Alignment::U64)?;
Ok(($($ty::decode(body)?,)*))
}
}
}
}
decode_tuple!(A);
decode_tuple!(A, B);
decode_tuple!(A, B, C);
decode_tuple!(A, B, C, D);
decode_tuple!(A, B, C, D, E);
decode_tuple!(A, B, C, D, E, F);
decode_tuple!(A, B, C, D, E, F, G);
decode_tuple!(A, B, C, D, E, F, G, H);
decode_tuple!(A, B, C, D, E, F, G, H, I);
decode_tuple!(A, B, C, D, E, F, G, H, I, J);
decode_tuple!(A, B, C, D, E, F, G, H, I, J, K);
decode_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);