initial commit

This commit is contained in:
Maple Nebel 2026-06-28 19:06:49 +02:00
commit 2814b0244e
10 changed files with 336 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View file

@ -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"

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "dbus-intervm-proxy"
version = "0.1.0"
edition = "2024"
authors = ["RusticMaple"]
[dependencies]

14
macros/Cargo.toml Normal file
View file

@ -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"

1
macros/src/lib.rs Normal file
View file

@ -0,0 +1 @@

3
src/dbus/mod.rs Normal file
View file

@ -0,0 +1,3 @@
//! D-Bus Abstractions
pub mod serialization;
pub mod types;

View file

@ -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;
}

286
src/dbus/types.rs Normal file
View file

@ -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<DbusType>),
/// 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, DbusTypeStrParseError<'a>> {
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<Self, DbusTypeParseError<'a>> {
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"),
}
}
}

5
src/lib.rs Normal file
View file

@ -0,0 +1,5 @@
#![deny(missing_docs)]
#![deny(clippy::undocumented_unsafe_blocks)]
//! D-Bus inter VM Proxy
pub mod dbus;

5
src/main.rs Normal file
View file

@ -0,0 +1,5 @@
#[allow(dead_code)]
mod dbus;
fn main() {
println!("Hello, world!");
}