initial commit
This commit is contained in:
commit
2814b0244e
10 changed files with 336 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal 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
7
Cargo.toml
Normal 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
14
macros/Cargo.toml
Normal 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
1
macros/src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
3
src/dbus/mod.rs
Normal file
3
src/dbus/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//! D-Bus Abstractions
|
||||
pub mod serialization;
|
||||
pub mod types;
|
||||
7
src/dbus/serialization.rs
Normal file
7
src/dbus/serialization.rs
Normal 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
286
src/dbus/types.rs
Normal 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
5
src/lib.rs
Normal 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
5
src/main.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#[allow(dead_code)]
|
||||
mod dbus;
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Loading…
Reference in a new issue