commit 2814b0244e4c0d5c337da56cbb21453a8ce26f90 Author: Maple Nebel Date: Sun Jun 28 19:06:49 2026 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3042615 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "dbus-intervm-proxy" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a12fb98 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dbus-intervm-proxy" +version = "0.1.0" +edition = "2024" +authors = ["RusticMaple"] + +[dependencies] diff --git a/macros/Cargo.toml b/macros/Cargo.toml new file mode 100644 index 0000000..9a75cb7 --- /dev/null +++ b/macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "dbus-macros" +version = "0.1.0" +edition = "2024" +authors = ["RusticMaple"] + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "~1.0", features = ["full"] } +quote = "~1.0" +proc-macro2 = "~1.0" +proc-macro-error = "~1.0" diff --git a/macros/src/lib.rs b/macros/src/lib.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/macros/src/lib.rs @@ -0,0 +1 @@ + diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs new file mode 100644 index 0000000..6bb4a60 --- /dev/null +++ b/src/dbus/mod.rs @@ -0,0 +1,3 @@ +//! D-Bus Abstractions +pub mod serialization; +pub mod types; diff --git a/src/dbus/serialization.rs b/src/dbus/serialization.rs new file mode 100644 index 0000000..fd59bf7 --- /dev/null +++ b/src/dbus/serialization.rs @@ -0,0 +1,7 @@ +//! Serialization utilities for D-Bus + +/// Trait for Objects which represent DBus De-/Serializable/Marschalable objects. +pub trait DBusMarshalable { + /// Get the D-Bus signature which represents this type + fn signature() -> &'static str; +} diff --git a/src/dbus/types.rs b/src/dbus/types.rs new file mode 100644 index 0000000..5d0ceb2 --- /dev/null +++ b/src/dbus/types.rs @@ -0,0 +1,286 @@ +//! Abstraction for the D-Bus type system. +//! +//! This module contains various types and abstractions to help model and deal with the D-Bus type system. +//! +//! For more details on D-Bus types see the [official freedesktop.org dbus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#type-system) + +use std::fmt::Display; + +/// This type represents a D-Bus type as described in the docs (see module documentation for more info on the spec) +/// +/// It can be instantiated either manually or from a D-Bus type signature: +/// ```rust +/// use dbus_intervm_proxy::dbus::types::DbusType::{self, *}; +/// // manually +/// let ty_1 = Array(Box::new(Struct(vec![I32, String, Map(Box::new((String, U32)))].into_boxed_slice()))); +/// // from type D-Bus type signature +/// let signature = "a(is{su})"; +/// let ty_2 = DbusType::new(signature).expect("invalid type signature"); +/// //both of these result in the same DbusType +/// assert_eq!(ty_1, ty_2); +/// ``` +/// +/// You can also get get the type signature from any given `DbusType`: +/// +/// ```rust +/// use dbus_intervm_proxy::dbus::types::DbusType; +/// // instantiate type from signature +/// let origin_signature = "a(is{su})"; +/// let ty = DbusType::new(origin_signature).expect("invalid type signature"); +/// // get signature from ty +/// let generated_signature = ty.to_string(); +/// // both signatures should be the same +/// assert_eq!(origin_signature, generated_signature); +/// ``` +#[derive(PartialEq, Eq, Debug, Clone, Hash)] +pub enum DbusType { + /// Byte, represented by `y` in Signatures + U8, + /// Boolean, represented by `b` in Signatures + Bool, + /// 16-bit signed integer, represented by `n` in Signatures + I16, + /// 16-bit unsigned integer, represented by `q` in Signatures + U16, + /// 32-bit signed integer, presented by `i` in Signatures + I32, + /// 32-bit unsigned integer, represented by `y` in Signatures + U32, + /// 64-bit signed integer, represented by `x` in Signatures + I64, + /// 64-bit unsigned integer, represented by `t` in Signatures + U64, + /// 64-bit floating point number(IEEE 754), represented by `d` in Signatures + F64, + /// Null terminated UTF-8 string, represented by `s` in Signatures + String, + /// Object instance name, represented by `o` in Signatures + ObjPath, + /// D-Bus type signature, represented by `g` in Signatures + Signature, + /// Array, represented by `a` in Signatures + Array(Box), + /// Struct/Tuple(can hold multiple other types), represented by `r`, `(` and `)` in Signatures + Struct(Box<[DbusType]>), + /// Variant(may be a value of any arbitrary DbusType, Type can only be deterimed at runtime), represented by `v` in Signatures + Variant, + /// Map/Dictionary, represented by `e`, `{` and `}` in Signatures + Map(Box<(DbusType, DbusType)>), + /// Unix file descriptor, represented by `h` in Signatures + FD, +} + +/// Error type for parsing D-Bus type signatures from a byte str. +#[derive(Debug)] +pub struct DbusTypeParseError<'a> { + text: &'a [u8], + position: usize, +} + +impl<'a> Display for DbusTypeParseError<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "Dbus type signature error, unexpected {} at position {} in {:?}: ", + self.position, + self.text + .get(self.position) + .map(|c| format!("{}", c)) + .unwrap_or("Eof".to_string()), + self.text + ) + } +} + +/// Error type for parsing D-Bus type signatures from a str. +#[derive(Debug)] +pub struct DbusTypeStrParseError<'a> { + text: &'a str, + position: usize, +} + +impl<'a> Display for DbusTypeStrParseError<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "Dbus type signature error, unexpected {} at position {} in {:?}: ", + self.position, + self.text + .chars() + .nth(self.position) + .map(|c| format!("\'{}\'", c)) + .unwrap_or("Eof".to_string()), + self.text + )?; + writeln!(f, "\t{}", self.text)?; + write!(f, "\t")?; + for _ in 0..self.position { + write!(f, " ")?; + } + write!(f, "^") + } +} + +impl DbusType { + /// Parses a D-Bus type signature. + /// + /// This function parses a dbus type signature. + /// It will only parse 1 type. + /// If there are multiple types in the given signature it will return an Error. + /// + /// # Panics + /// Panics if signature is empty. + /// + /// # Examples + /// Basic usage: + /// ```rust + /// use dbus_intervm_proxy::dbus::types::DbusType::{self, *}; + /// let signature = "a(is{su})"; + /// let ty = DbusType::new(signature).expect("invalid type signature"); + /// + /// assert_eq!(ty, Array(Box::new(Struct(vec![I32, String, Map(Box::new((String, U32)))].into_boxed_slice())))); + /// ``` + pub fn new<'a>(signature: &'a str) -> Result> { + Self::from_byte_str(signature.as_bytes()).map_err(|v| DbusTypeStrParseError { + text: signature, + position: v.position, + }) + } + + /// Parses a D-Bus type signature from a byte str. + /// + /// This function parses a dbus type signature. + /// It will only parse 1 type. + /// If there are multiple types in the given signature it will return an Error. + /// + /// # Panics + /// Panics if signature is empty. + /// + /// # Examples + /// Basic usage: + /// ```rust + /// use dbus_intervm_proxy::dbus::types::DbusType::{self, *}; + /// let signature = b"a(is{su})"; + /// let ty = DbusType::from_byte_str(signature).expect("invalid type signature"); + /// + /// assert_eq!(ty, Array(Box::new(Struct(vec![I32, String, Map(Box::new((String, U32)))].into_boxed_slice())))); + /// ``` + pub fn from_byte_str<'a>(signature: &'a [u8]) -> Result> { + match Self::parse_piece(signature) { + Ok((val, &[])) => Ok(val), + Ok((_, rest)) => { + let position = signature.element_offset(&rest[0]).unwrap(); + Err(DbusTypeParseError { + position, + text: signature, + }) + } + Err(e) => { + let position = match e { + Some(e) => signature.element_offset(e).unwrap(), + None => signature.len(), + }; + Err(DbusTypeParseError { + position, + text: signature, + }) + } + } + } + + /// Parses a D-Bus type and gives back the type and the leftover from parsing + /// + /// This function will parse a piece of a D-Bus type signature. + /// It returns both the type which was parsed from the signature and the rest + /// of the signature which isnt contained within the type we give as the first + /// return value. + /// + /// This is used internally to parse more complex types such as array or structs + /// as those require parsing multiple types in a row until hitting a delimiter + /// + /// If the return is Err(None) that means that we hit an unexpected Eof + fn parse_piece<'a>(signature: &'a [u8]) -> Result<(Self, &'a [u8]), Option<&'a u8>> { + match signature { + [b'y', rest @ ..] => Ok((Self::U8, rest)), + [b'b', rest @ ..] => Ok((Self::Bool, rest)), + [b'n', rest @ ..] => Ok((Self::I16, rest)), + [b'q', rest @ ..] => Ok((Self::U16, rest)), + [b'i', rest @ ..] => Ok((Self::I32, rest)), + [b'u', rest @ ..] => Ok((Self::U32, rest)), + [b'x', rest @ ..] => Ok((Self::I64, rest)), + [b't', rest @ ..] => Ok((Self::U64, rest)), + [b'd', rest @ ..] => Ok((Self::F64, rest)), + [b's', rest @ ..] => Ok((Self::String, rest)), + [b'o', rest @ ..] => Ok((Self::ObjPath, rest)), + [b'g', rest @ ..] => Ok((Self::Signature, rest)), + [b'v', rest @ ..] => Ok((Self::Variant, rest)), + [b'h', rest @ ..] => Ok((Self::FD, rest)), + [b'a', rest @ ..] => { + let (ty, rest) = Self::parse_piece(rest)?; + Ok((Self::Array(Box::new(ty)), rest)) + } + [b'{', rest @ ..] => { + let (piece_1, rest) = Self::parse_piece(rest)?; + let (piece_2, rest) = Self::parse_piece(rest)?; + match rest { + [] => return Err(None), + [b'}', rest @ ..] => { + return Ok((Self::Map(Box::new((piece_1, piece_2))), rest)); + } + _ => return Err(Some(&rest[0])), + } + } + [b'(', rest @ ..] => { + let mut rest = rest; + let mut contained = vec![]; + loop { + match rest { + [] => return Err(None), + [b')', rest @ ..] => { + return Ok((Self::Struct(contained.into_boxed_slice()), rest)); + } + _ => {} + } + + let (piece, new_rest) = Self::parse_piece(rest)?; + contained.push(piece); + rest = new_rest; + } + } + [] => return Err(None), + _ => return Err(Some(&signature[0])), + } + } +} + +impl Display for DbusType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DbusType::U8 => write!(f, "y"), + DbusType::Bool => write!(f, "b"), + DbusType::I16 => write!(f, "n"), + DbusType::U16 => write!(f, "q"), + DbusType::I32 => write!(f, "i"), + DbusType::U32 => write!(f, "u"), + DbusType::I64 => write!(f, "x"), + DbusType::U64 => write!(f, "t"), + DbusType::F64 => write!(f, "d"), + DbusType::String => write!(f, "s"), + DbusType::ObjPath => write!(f, "o"), + DbusType::Signature => write!(f, "g"), + DbusType::Array(dbus_type) => write!(f, "a{}", dbus_type), + DbusType::Struct(dbus_types) => { + write!(f, "(")?; + for dbus_type in dbus_types { + write!(f, "{}", dbus_type)?; + } + write!(f, ")") + } + DbusType::Variant => write!(f, "v"), + DbusType::Map(dbus_types) => { + write!(f, "{{{}{}}}", dbus_types.as_ref().0, dbus_types.as_ref().1) + } + DbusType::FD => write!(f, "h"), + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..038b171 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +#![deny(missing_docs)] +#![deny(clippy::undocumented_unsafe_blocks)] +//! D-Bus inter VM Proxy + +pub mod dbus; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..81b14fc --- /dev/null +++ b/src/main.rs @@ -0,0 +1,5 @@ +#[allow(dead_code)] +mod dbus; +fn main() { + println!("Hello, world!"); +}