use serde::{
de::{self, DeserializeSeed, VariantAccess, Visitor},
Deserialize,
};
use std::{marker::PhantomData, os::unix::io::RawFd, str};
#[cfg(feature = "gvariant")]
use crate::gvariant::Deserializer as GVDeserializer;
use crate::{
dbus::Deserializer as DBusDeserializer, signature_parser::SignatureParser, utils::*, Basic,
EncodingContext, EncodingFormat, Error, Fd, ObjectPath, Result, Signature, Type,
};
pub fn from_slice_fds<'d, 'r: 'd, B, T: ?Sized>(
bytes: &'r [u8],
fds: Option<&[RawFd]>,
ctxt: EncodingContext<B>,
) -> Result<T>
where
B: byteorder::ByteOrder,
T: Deserialize<'d> + Type,
{
let signature = T::signature();
from_slice_fds_for_signature(bytes, fds, ctxt, &signature)
}
pub fn from_slice<'d, 'r: 'd, B, T: ?Sized>(bytes: &'r [u8], ctxt: EncodingContext<B>) -> Result<T>
where
B: byteorder::ByteOrder,
T: Deserialize<'d> + Type,
{
let signature = T::signature();
from_slice_for_signature(bytes, ctxt, &signature)
}
pub fn from_slice_for_signature<'d, 'r: 'd, B, T: ?Sized>(
bytes: &'r [u8],
ctxt: EncodingContext<B>,
signature: &Signature<'_>,
) -> Result<T>
where
B: byteorder::ByteOrder,
T: Deserialize<'d>,
{
from_slice_fds_for_signature(bytes, None, ctxt, signature)
}
pub fn from_slice_fds_for_signature<'d, 'r: 'd, B, T: ?Sized>(
bytes: &'r [u8],
fds: Option<&[RawFd]>,
ctxt: EncodingContext<B>,
signature: &Signature<'_>,
) -> Result<T>
where
B: byteorder::ByteOrder,
T: Deserialize<'d>,
{
let mut de = match ctxt.format() {
#[cfg(feature = "gvariant")]
EncodingFormat::GVariant => {
Deserializer::GVariant(GVDeserializer::new(bytes, fds, signature, ctxt))
}
EncodingFormat::DBus => {
Deserializer::DBus(DBusDeserializer::new(bytes, fds, signature, ctxt))
}
};
T::deserialize(&mut de)
}
#[derive(Debug)]
pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B> {
pub(crate) ctxt: EncodingContext<B>,
pub(crate) bytes: &'de [u8],
pub(crate) fds: Option<&'f [RawFd]>,
pub(crate) pos: usize,
pub(crate) sig_parser: SignatureParser<'sig>,
pub(crate) b: PhantomData<B>,
}
pub enum Deserializer<'ser, 'sig, 'f, B> {
DBus(DBusDeserializer<'ser, 'sig, 'f, B>),
#[cfg(feature = "gvariant")]
GVariant(GVDeserializer<'ser, 'sig, 'f, B>),
}
impl<'de, 'sig, 'f, B> Deserializer<'de, 'sig, 'f, B>
where
B: byteorder::ByteOrder,
{
pub fn new<'r: 'de>(
bytes: &'r [u8],
fds: Option<&'f [RawFd]>,
signature: &Signature<'sig>,
ctxt: EncodingContext<B>,
) -> Self {
match ctxt.format() {
#[cfg(feature = "gvariant")]
EncodingFormat::GVariant => {
Self::GVariant(GVDeserializer::new(bytes, fds, signature, ctxt))
}
EncodingFormat::DBus => Self::DBus(DBusDeserializer::new(bytes, fds, signature, ctxt)),
}
}
}
impl<'de, 'sig, 'f, B> DeserializerCommon<'de, 'sig, 'f, B>
where
B: byteorder::ByteOrder,
{
pub fn get_fd(&self, idx: u32) -> Result<i32> {
self.fds
.map(|fds| fds.get(idx as usize))
.flatten()
.copied()
.ok_or(Error::UnknownFd)
}
pub fn parse_padding(&mut self, alignment: usize) -> Result<usize> {
let padding = padding_for_n_bytes(self.abs_pos(), alignment);
if padding > 0 {
if self.pos + padding > self.bytes.len() {
return Err(serde::de::Error::invalid_length(
self.bytes.len(),
&format!(">= {}", self.pos + padding).as_str(),
));
}
for i in 0..padding {
let byte = self.bytes[self.pos + i];
if byte != 0 {
return Err(Error::PaddingNot0(byte));
}
}
self.pos += padding;
}
Ok(padding)
}
pub fn prep_deserialize_basic<T>(&mut self) -> Result<()>
where
T: Basic,
{
self.sig_parser.skip_char()?;
self.parse_padding(T::alignment(self.ctxt.format()))?;
Ok(())
}
pub fn next_slice(&mut self, len: usize) -> Result<&'de [u8]> {
if self.pos + len > self.bytes.len() {
return Err(serde::de::Error::invalid_length(
self.bytes.len(),
&format!(">= {}", self.pos + len).as_str(),
));
}
let slice = &self.bytes[self.pos..self.pos + len];
self.pos += len;
Ok(slice)
}
pub fn next_const_size_slice<T>(&mut self) -> Result<&[u8]>
where
T: Basic,
{
self.prep_deserialize_basic::<T>()?;
self.next_slice(T::alignment(self.ctxt.format()))
}
pub fn abs_pos(&self) -> usize {
self.ctxt.position() + self.pos
}
}
macro_rules! deserialize_method {
($method:ident($($arg:ident: $type:ty),*)) => {
#[inline]
fn $method<V>(self, $($arg: $type,)* visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self {
#[cfg(feature = "gvariant")]
Deserializer::GVariant(de) => {
de.$method($($arg,)* visitor)
}
Deserializer::DBus(de) => {
de.$method($($arg,)* visitor)
}
}
}
}
}
impl<'de, 'd, 'sig, 'f, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B>
where
B: byteorder::ByteOrder,
{
type Error = Error;
deserialize_method!(deserialize_any());
deserialize_method!(deserialize_bool());
deserialize_method!(deserialize_i8());
deserialize_method!(deserialize_i16());
deserialize_method!(deserialize_i32());
deserialize_method!(deserialize_i64());
deserialize_method!(deserialize_u8());
deserialize_method!(deserialize_u16());
deserialize_method!(deserialize_u32());
deserialize_method!(deserialize_u64());
deserialize_method!(deserialize_f32());
deserialize_method!(deserialize_f64());
deserialize_method!(deserialize_char());
deserialize_method!(deserialize_str());
deserialize_method!(deserialize_string());
deserialize_method!(deserialize_bytes());
deserialize_method!(deserialize_byte_buf());
deserialize_method!(deserialize_option());
deserialize_method!(deserialize_unit());
deserialize_method!(deserialize_unit_struct(n: &'static str));
deserialize_method!(deserialize_newtype_struct(n: &'static str));
deserialize_method!(deserialize_seq());
deserialize_method!(deserialize_map());
deserialize_method!(deserialize_tuple(n: usize));
deserialize_method!(deserialize_tuple_struct(n: &'static str, l: usize));
deserialize_method!(deserialize_struct(
n: &'static str,
f: &'static [&'static str]
));
deserialize_method!(deserialize_enum(
n: &'static str,
f: &'static [&'static str]
));
deserialize_method!(deserialize_identifier());
deserialize_method!(deserialize_ignored_any());
}
#[derive(Debug)]
pub(crate) enum ValueParseStage {
Signature,
Value,
Done,
}
pub(crate) fn deserialize_any<'de, 'sig, 'f, B, D, V>(
de: D,
next_char: char,
visitor: V,
) -> Result<V::Value>
where
D: de::Deserializer<'de, Error = Error>,
V: Visitor<'de>,
B: byteorder::ByteOrder,
{
match next_char {
u8::SIGNATURE_CHAR => de.deserialize_u8(visitor),
bool::SIGNATURE_CHAR => de.deserialize_bool(visitor),
i16::SIGNATURE_CHAR => de.deserialize_i16(visitor),
u16::SIGNATURE_CHAR => de.deserialize_u16(visitor),
i32::SIGNATURE_CHAR | Fd::SIGNATURE_CHAR => de.deserialize_i32(visitor),
u32::SIGNATURE_CHAR => de.deserialize_u32(visitor),
i64::SIGNATURE_CHAR => de.deserialize_i64(visitor),
u64::SIGNATURE_CHAR => de.deserialize_u64(visitor),
f64::SIGNATURE_CHAR => de.deserialize_f64(visitor),
<&str>::SIGNATURE_CHAR | ObjectPath::SIGNATURE_CHAR | Signature::SIGNATURE_CHAR => {
de.deserialize_str(visitor)
}
VARIANT_SIGNATURE_CHAR => de.deserialize_seq(visitor),
ARRAY_SIGNATURE_CHAR => de.deserialize_seq(visitor),
STRUCT_SIG_START_CHAR => de.deserialize_seq(visitor),
#[cfg(feature = "gvariant")]
MAYBE_SIGNATURE_CHAR => de.deserialize_option(visitor),
c => Err(de::Error::invalid_value(
de::Unexpected::Char(c),
&"a valid signature character",
)),
}
}
pub(crate) trait GetDeserializeCommon<'de, 'sig, 'f, B>
where
B: byteorder::ByteOrder,
{
fn common_mut<'d>(self) -> &'d mut DeserializerCommon<'de, 'sig, 'f, B>
where
Self: 'd;
}
pub(crate) struct Enum<B, D> {
pub(crate) de: D,
pub(crate) name: &'static str,
pub(crate) phantom: PhantomData<B>,
}
impl<'de, 'sig, 'f, B, D> VariantAccess<'de> for Enum<B, D>
where
B: byteorder::ByteOrder,
D: de::Deserializer<'de, Error = Error> + GetDeserializeCommon<'de, 'sig, 'f, B>,
{
type Error = Error;
fn unit_variant(self) -> std::result::Result<(), Self::Error> {
self.de.common_mut().sig_parser.skip_char()
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_struct(self.de, self.name, &[], visitor)
}
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_struct(self.de, self.name, fields, visitor)
}
}