Skip to content

Commit

Permalink
⚡️ zv: Avoid allocation for FD list
Browse files Browse the repository at this point in the history
Make use of generics and `AsFd` trait to avoid unnecessary allocation of
FD list.
  • Loading branch information
zeenix committed Oct 27, 2023
1 parent 10dca2e commit 6203d54
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 124 deletions.
75 changes: 43 additions & 32 deletions zvariant/src/dbus/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use static_assertions::assert_impl_all;
use std::{marker::PhantomData, str};

#[cfg(unix)]
use std::os::unix::io::RawFd;
use std::os::fd::AsFd;

use crate::{
de::{DeserializerCommon, ValueParseStage},
Expand All @@ -18,11 +18,13 @@ use crate::Fd;

/// Our D-Bus deserialization implementation.
#[derive(Debug)]
pub(crate) struct Deserializer<'de, 'sig, 'f, B>(pub(crate) DeserializerCommon<'de, 'sig, 'f, B>);
pub(crate) struct Deserializer<'de, 'sig, 'f, B, F>(
pub(crate) DeserializerCommon<'de, 'sig, 'f, B, F>,
);

assert_impl_all!(Deserializer<'_, '_, '_, i32>: Send, Sync, Unpin);
assert_impl_all!(Deserializer<'_, '_, '_, i32, ()>: Send, Sync, Unpin);

impl<'de, 'sig, 'f, B> Deserializer<'de, 'sig, 'f, B>
impl<'de, 'sig, 'f, B, F> Deserializer<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand All @@ -31,7 +33,7 @@ where
/// On Windows, there is no `fds` argument.
pub fn new<'r: 'de, S>(
bytes: &'r [u8],
#[cfg(unix)] fds: Option<&'f [RawFd]>,
#[cfg(unix)] fds: Option<&'f [F]>,
signature: S,
ctxt: EncodingContext<B>,
) -> Result<Self>
Expand Down Expand Up @@ -86,7 +88,8 @@ macro_rules! deserialize_as {
}
}

impl<'de, 'd, 'sig, 'f, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B>
impl<'de, 'd, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deserializer<'de>
for &'d mut Deserializer<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand Down Expand Up @@ -367,7 +370,7 @@ where
let v = visitor.visit_enum(crate::de::Enum {
de: &mut *self,
name,
phantom: PhantomData,
_phantoms: (PhantomData, PhantomData),
})?;

if non_unit {
Expand All @@ -394,8 +397,8 @@ where
}
}

struct ArrayDeserializer<'d, 'de, 'sig, 'f, B> {
de: &'d mut Deserializer<'de, 'sig, 'f, B>,
struct ArrayDeserializer<'d, 'de, 'sig, 'f, B, F> {
de: &'d mut Deserializer<'de, 'sig, 'f, B, F>,
len: usize,
start: usize,
// alignment of element
Expand All @@ -404,11 +407,12 @@ struct ArrayDeserializer<'d, 'de, 'sig, 'f, B> {
element_signature_len: usize,
}

impl<'d, 'de, 'sig, 'f, B> ArrayDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>
ArrayDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Result<Self> {
fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B, F>) -> Result<Self> {
de.0.parse_padding(ARRAY_ALIGNMENT_DBUS)?;
de.0.container_depths = de.0.container_depths.inc_array()?;

Expand Down Expand Up @@ -442,7 +446,7 @@ where
{
let ctxt = EncodingContext::new_dbus(self.de.0.ctxt.position() + self.de.0.pos);

let mut de = Deserializer::<B>(DeserializerCommon {
let mut de = Deserializer::<B, F>(DeserializerCommon {
ctxt,
sig_parser,
bytes: subslice(self.de.0.bytes, self.de.0.pos..)?,
Expand Down Expand Up @@ -493,7 +497,9 @@ where
}
}

fn deserialize_ay<'de, B>(de: &mut Deserializer<'de, '_, '_, B>) -> Result<&'de [u8]>
fn deserialize_ay<'de, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>(
de: &mut Deserializer<'de, '_, '_, B, F>,
) -> Result<&'de [u8]>
where
B: byteorder::ByteOrder,
{
Expand All @@ -508,9 +514,10 @@ where
de.0.next_slice(len)
}

struct ArraySeqDeserializer<'d, 'de, 'sig, 'f, B>(ArrayDeserializer<'d, 'de, 'sig, 'f, B>);
struct ArraySeqDeserializer<'d, 'de, 'sig, 'f, B, F>(ArrayDeserializer<'d, 'de, 'sig, 'f, B, F>);

impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for ArraySeqDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de>
for ArraySeqDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand All @@ -525,9 +532,10 @@ where
}
}

struct ArrayMapDeserializer<'d, 'de, 'sig, 'f, B>(ArrayDeserializer<'d, 'de, 'sig, 'f, B>);
struct ArrayMapDeserializer<'d, 'de, 'sig, 'f, B, F>(ArrayDeserializer<'d, 'de, 'sig, 'f, B, F>);

impl<'d, 'de, 'sig, 'f, B> MapAccess<'de> for ArrayMapDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de>
for ArrayMapDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand All @@ -553,11 +561,12 @@ where
}

#[derive(Debug)]
struct StructureDeserializer<'d, 'de, 'sig, 'f, B> {
de: &'d mut Deserializer<'de, 'sig, 'f, B>,
struct StructureDeserializer<'d, 'de, 'sig, 'f, B, F> {
de: &'d mut Deserializer<'de, 'sig, 'f, B, F>,
}

impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for StructureDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de>
for StructureDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand All @@ -579,27 +588,29 @@ where
}

#[derive(Debug)]
struct ValueDeserializer<'d, 'de, 'sig, 'f, B> {
de: &'d mut Deserializer<'de, 'sig, 'f, B>,
struct ValueDeserializer<'d, 'de, 'sig, 'f, B, F> {
de: &'d mut Deserializer<'de, 'sig, 'f, B, F>,
stage: ValueParseStage,
sig_start: usize,
}

impl<'d, 'de, 'sig, 'f, B> ValueDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>
ValueDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Self {
fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B, F>) -> Self {
let sig_start = de.0.pos;
ValueDeserializer::<B> {
ValueDeserializer::<B, F> {
de,
stage: ValueParseStage::Signature,
sig_start,
}
}
}

impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for ValueDeserializer<'d, 'de, 'sig, 'f, B>
impl<'d, 'de, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de>
for ValueDeserializer<'d, 'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand Down Expand Up @@ -633,7 +644,7 @@ where
EncodingFormat::DBus,
self.de.0.ctxt.position() + value_start,
);
let mut de = Deserializer::<B>(DeserializerCommon {
let mut de = Deserializer::<B, F>(DeserializerCommon {
ctxt,
sig_parser,
bytes: subslice(self.de.0.bytes, value_start..)?,
Expand All @@ -653,21 +664,21 @@ where
}
}

impl<'de, 'd, 'sig, 'f, B> crate::de::GetDeserializeCommon<'de, 'sig, 'f, B>
for &'d mut Deserializer<'de, 'sig, 'f, B>
impl<'de, 'd, 'sig, 'f, B, F> crate::de::GetDeserializeCommon<'de, 'sig, 'f, B, F>
for &'d mut Deserializer<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
fn common_mut<'dr>(self) -> &'dr mut DeserializerCommon<'de, 'sig, 'f, B>
fn common_mut<'dr>(self) -> &'dr mut DeserializerCommon<'de, 'sig, 'f, B, F>
where
Self: 'dr,
{
&mut self.0
}
}

impl<'de, 'd, 'sig, 'f, B> EnumAccess<'de>
for crate::de::Enum<B, &'d mut Deserializer<'de, 'sig, 'f, B>>
impl<'de, 'd, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> EnumAccess<'de>
for crate::de::Enum<B, &'d mut Deserializer<'de, 'sig, 'f, B, F>, F>
where
B: byteorder::ByteOrder,
{
Expand Down
45 changes: 25 additions & 20 deletions zvariant/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use static_assertions::assert_impl_all;
use std::{marker::PhantomData, str};

#[cfg(unix)]
use std::os::unix::io::RawFd;
use std::os::fd::{AsFd, AsRawFd};

#[cfg(feature = "gvariant")]
use crate::gvariant::Deserializer as GVDeserializer;
Expand All @@ -19,14 +19,14 @@ use crate::Fd;

/// Our deserialization implementation.
#[derive(Debug)]
pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B> {
pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B, F> {
pub(crate) ctxt: EncodingContext<B>,
pub(crate) bytes: &'de [u8],

#[cfg(unix)]
pub(crate) fds: Option<&'f [RawFd]>,
pub(crate) fds: Option<&'f [F]>,
#[cfg(not(unix))]
pub(crate) fds: PhantomData<&'f ()>,
pub(crate) fds: PhantomData<&'f F>,

pub(crate) pos: usize,

Expand All @@ -42,26 +42,30 @@ pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B> {
/// Using this deserializer involves an redirection to the actual deserializer. It's best
/// to use the serialization functions, e.g [`crate::to_bytes`] or specific serializers,
/// [`crate::dbus::Deserializer`] or [`crate::zvariant::Deserializer`].
pub(crate) enum Deserializer<'ser, 'sig, 'f, B> {
DBus(DBusDeserializer<'ser, 'sig, 'f, B>),
pub(crate) enum Deserializer<'ser, 'sig, 'f, B, F> {
DBus(DBusDeserializer<'ser, 'sig, 'f, B, F>),
#[cfg(feature = "gvariant")]
GVariant(GVDeserializer<'ser, 'sig, 'f, B>),
GVariant(GVDeserializer<'ser, 'sig, 'f, B, F>),
}

assert_impl_all!(Deserializer<'_, '_, '_, u8>: Send, Sync, Unpin);
assert_impl_all!(Deserializer<'_, '_, '_, u8, ()>: Send, Sync, Unpin);

impl<'de, 'sig, 'f, B> DeserializerCommon<'de, 'sig, 'f, B>
#[cfg(unix)]
impl<'de, 'sig, 'f, B, F> DeserializerCommon<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
F: AsFd,
{
#[cfg(unix)]
pub fn get_fd(&self, idx: u32) -> Result<i32> {
self.fds
.and_then(|fds| fds.get(idx as usize))
.copied()
.and_then(|fds| fds.get(idx as usize).map(|fd| fd.as_fd().as_raw_fd()))
.ok_or(Error::UnknownFd)
}
}

impl<'de, 'sig, 'f, B, F> DeserializerCommon<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
pub fn parse_padding(&mut self, alignment: usize) -> Result<usize> {
let padding = padding_for_n_bytes(self.abs_pos(), alignment);
if padding > 0 {
Expand Down Expand Up @@ -142,7 +146,8 @@ macro_rules! deserialize_method {
}
}

impl<'de, 'd, 'sig, 'f, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B>
impl<'de, 'd, 'sig, 'f, B, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deserializer<'de>
for &'d mut Deserializer<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
Expand Down Expand Up @@ -232,26 +237,26 @@ where
}
}

pub(crate) trait GetDeserializeCommon<'de, 'sig, 'f, B>
pub(crate) trait GetDeserializeCommon<'de, 'sig, 'f, B, F>
where
B: byteorder::ByteOrder,
{
fn common_mut<'d>(self) -> &'d mut DeserializerCommon<'de, 'sig, 'f, B>
fn common_mut<'d>(self) -> &'d mut DeserializerCommon<'de, 'sig, 'f, B, F>
where
Self: 'd;
}

// Enum handling is very generic so it can be here and specific deserializers can use this.
pub(crate) struct Enum<B, D> {
pub(crate) struct Enum<B, D, F> {
pub(crate) de: D,
pub(crate) name: &'static str,
pub(crate) phantom: PhantomData<B>,
pub(crate) _phantoms: (PhantomData<B>, PhantomData<F>),
}

impl<'de, 'sig, 'f, B, D> VariantAccess<'de> for Enum<B, D>
impl<'de, 'sig, 'f, B, D, F> VariantAccess<'de> for Enum<B, D, F>
where
B: byteorder::ByteOrder,
D: de::Deserializer<'de, Error = Error> + GetDeserializeCommon<'de, 'sig, 'f, B>,
D: de::Deserializer<'de, Error = Error> + GetDeserializeCommon<'de, 'sig, 'f, B, F>,
{
type Error = Error;

Expand Down
Loading

0 comments on commit 6203d54

Please sign in to comment.