Zeeshan Ali Khan
About myself
Open Source & Linux Systems Engineer
JUCR
⌁
What's zbus?
Pure Rust D-Bus library
Ok and WTH is D-Bus?
Effecient binary IPC protocol
Before zbus..
There was only dbus-rs
libdbus wrapper
Multiple issues
zbus
Goto D-Bus crate
What's the problem then?
Before we go there..
zvariant
serde-based since 2.0
Fundamental incompatibilites
Option<T>
No Nullable types in D-Bus
Empty Array Alignment
wikipedia.org/wiki/Data_structure_alignment
impl serde::Serializer for MySerializer { type SerializeSeq = MySeqSerializer; ... fn serialize_seq( self, len: Option<usize>, ) -> Result<Self::SerializeSeq, Self::Error> { unimplemented!() } }
impl serde::SerializeSeq for MySeqSerializer { ... // Never called for empty sequences. fn serialize_element<T: ?Sized + Serialize>( &mut self, value: &T, ) -> Result<(), Self::Error> { unimplemented!() } fn end(self) -> Result<(), Self::Error> { unimplemented!() } }
How did I solve it?
Enter D-Bus type signatures
(iba{sv})
Type trait
Type
// over-simplified. struct Signature<'a>(Cow<'a, str>); trait Type { fn signature() -> Signature<'static>; } trait DynamicType { fn dynamic_signature(&self) -> Signature<'_>; }
Meh!
Type derive
#[derive(Serialize, Deserialize, Type)] // ^^^^ struct MyStruct { a: u32, b: String, c: Vec<u8>, }
impls for commonly used types
Including external crates
e.g chrono, uuid, etc
chrono
uuid
Too many allocations
Not const
const
Oh well.
What about performance?
https://github.com/KillingSpark/rust-dbus-comparisons
cargo bench + criterion
cargo bench
criterion
Not too bad?
Bar is low
Biggest bottleneck?
Introducing cargo flamegraph
cargo flamegraph
Signature parsing
Especially large arrays
Many sleepless nights
Years go by..
postcard & postcard-rpc
postcard
postcard-rpc
trait Schema { const SCHEMA: &'static NamedType; }
Rethink Signature Representation
enum Signature { Unit, Bool, Byte, Int16, ... Array(Child), Struct(Fields), Dict { key: Child, value: Child }, }
enum Child { /// A static child signature. Static { child: &'static Signature }, /// A dynamic child signature. Dynamic { child: Box<Signature> }, } enum Fields { Static { fields: &'static [&'static Signature] }, Dynamic { fields: Box<[Signature]> }, }
trait Type { const SIGNATURE: &'static Signature; } trait DynamicType { fn signature(&self) -> Signature; }
(De)serializer don't parse anymore ️
Well, not exactly..
Variants
More robust & efficient parser
nom
winnow
Parse once
It works!!
Performs better?
You promised 95%!
Hardware-dependent
Type-dependent
The Future?
Varlink
JSON
Better serde-compatiblity
Parsing costs?
Context-switching is expensive
p2p
Other optimization opportunities
Many connections -> exterior mutability
Avoid allocations/cloning
no-std
no-alloc
A Rust crate exists
Guess the name?
Yes, it's Varlink
A few issues
We can do better
I have a plan
A bit vague but...
...based on experience
The same crate (hopefully!)
D-Bus not going away
Legacy
https://github.com/dbus2/zbus