Bug 1429847 - Vendor rust, to pick up the changes. r=kinetik

Differential Revision: https://phabricator.services.mozilla.com/D30907

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Paul Adenot 2019-06-21 19:51:22 +00:00
parent be02258965
commit 6af26dcc3d
84 changed files with 11981 additions and 0 deletions

45
Cargo.lock generated
View File

@ -76,6 +76,19 @@ dependencies = [
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
]
[[package]]
name = "audio_thread_priority"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
]
[[package]]
name = "audioipc"
version = "0.2.4"
@ -105,6 +118,7 @@ name = "audioipc-client"
version = "0.4.0"
dependencies = [
"audioipc 0.2.4",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-backend 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -119,6 +133,7 @@ dependencies = [
name = "audioipc-server"
version = "0.2.3"
dependencies = [
"audio_thread_priority 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc 0.2.4",
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -853,6 +868,15 @@ dependencies = [
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dbus"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"libdbus-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "deflate"
version = "0.7.19"
@ -1215,6 +1239,7 @@ name = "gkrust-shared"
version = "0.1.0"
dependencies = [
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"audio_thread_priority 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc-client 0.4.0",
"audioipc-server 0.2.3",
"authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1527,6 +1552,14 @@ name = "libc"
version = "0.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libdbus-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libloading"
version = "0.5.0"
@ -1619,6 +1652,14 @@ name = "lzw"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mach"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "malloc_size_of"
version = "0.0.1"
@ -3613,6 +3654,7 @@ dependencies = [
"checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum audio_thread_priority 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cff72a47c1869175a49a79bfeae945f4e68b4bb8567fb14d4c0de61800b4bd4"
"checksum authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ec149e5d5d4caa2c9ead53a8ce1ea9c4204c388c65bf3b96c2d1dc0fcf4aeb66"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
@ -3679,6 +3721,7 @@ dependencies = [
"checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6"
"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c"
"checksum darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1"
"checksum dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e1b39f3f6aa3d4a1522c4f0f9f1e9e9167bd93740a8690874caa7cf8ce47d7"
"checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
"checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871"
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
@ -3736,6 +3779,7 @@ dependencies = [
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
"checksum libdbus-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "18cb88963258d00f4962205dbb5933d82780d9962c8c8a064b651d2ad7189210"
"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
"checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
@ -3746,6 +3790,7 @@ dependencies = [
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
"checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"e2309a985567d6ff4ef0e565f99b881db689d335fecb4ad4a8f801751cbf83d8","Makefile":"8c6b9e8afffb14ae03f9cd95bc7d6011c8b4fe01c474aef17360e3f0c4d202ad","README.md":"bcfa4948edf52fdacd485200a0c1c886a92232cc1931eeb4e1044050f46ec253","audio_thread_priority.h":"880889a154283a87cf84218cc4d6b2b9dd2c8fd09adc6d38f527b08ccd0c6168","generate_osx_bindings.sh":"06e4e03450f788ced18d31fff5660919e6f6ec1119ddace363ffeb82f0518a71","src/lib.rs":"69f428f49b61d2fa3ec5e1a04e5a07e876db2076d432f32e5710633d423b4db6","src/mach_sys.rs":"352560fcb9b41d877cff92e5b3b04d6dc68b1f30508ce4b9aed78940120a883e","src/rt_linux.rs":"2b3ee3b42690a050cd50f5b4056160bd4e7241b53409dab188511e6647b8b956","src/rt_mach.rs":"353c768775e1ac7daf9464d0a63ecc002f1e317ce00a835b63900bc036bedda2","src/rt_win.rs":"41fcdb22a9e7f5b6b389bb0791324bccbaecf8523dbef62b224a81d37e780039"},"package":"6cff72a47c1869175a49a79bfeae945f4e68b4bb8567fb14d4c0de61800b4bd4"}

View File

@ -0,0 +1,48 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "audio_thread_priority"
version = "0.13.0"
authors = ["Paul Adenot <paul@paul.cx>"]
description = "Bump a thread to real-time priority, for audio work, on Linux, Windows and macOS"
license = "MPL-2.0"
repository = "https://github.com/padenot/audio_thread_priority"
[lib]
name = "audio_thread_priority"
crate-type = ["staticlib", "rlib"]
[dependencies.cfg-if]
version = "0.1"
[dependencies.log]
version = "0.4"
[dependencies.simple_logger]
version = "0.4"
optional = true
[features]
terminal-logging = ["simple_logger"]
[target."cfg(target_os = \"linux\")".dependencies.dbus]
version = "0.6.4"
[target."cfg(target_os = \"linux\")".dependencies.libc]
version = "0.2"
[target."cfg(target_os = \"macos\")".dependencies.libc]
version = "0.2"
[target."cfg(target_os = \"macos\")".dependencies.mach]
version = "0.1"
[target."cfg(target_os = \"windows\")".dependencies.winapi]
version = "0.3"
features = ["avrt", "errhandlingapi", "ntdef", "minwindef"]

View File

@ -0,0 +1,5 @@
all: target/debug/libaudio_thread_priority.a
g++ atp_test.cpp target/debug/libaudio_thread_priority.a -I. -lpthread -ldbus-1 -ldl -g
target/debug/libaudio_thread_priority.a:
cargo build

View File

@ -0,0 +1,37 @@
# audio_thread_priority
Synopsis:
```rust
// ... on a thread that will compute audio and has to be real-time:
RtPriorityHandle handle;
match promote_current_thread_to_real_time(512, 44100) {
Ok(h) => {
handle = h;
println!("this thread is now bumped to real-time priority.")
}
Err(...) => { println!("could not bump to real time.") }
}
// do some real-time work.
match demote_current_thread_from_real_time(h) {
Ok(...) => {
println!("this thread is now bumped back to normal.")
}
Err(...) => {
println!("Could not bring the thread back to normal priority.")
}
}
```
This library can also be used from C or C++ using the included header and
compiling the rust code in the application. By default, a `.a` is compiled to
ease linking.
# License
MPL-2

View File

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AUDIO_THREAD_PRIORITY_H
#define AUDIO_THREAD_PRIORITY_H
#include <stdint.h>
#include <stdlib.h>
/**
* An opaque structure containing information about a thread that was promoted
* to real-time priority.
*/
struct atp_handle;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Promotes the current thread to real-time priority.
*
* audio_buffer_frames: number of frames per audio buffer. If unknown, passing 0
* will choose an appropriate number, conservatively. If variable, either pass 0
* or an upper bound.
* audio_samplerate_hz: sample-rate for this audio stream, in Hz
*
* Returns an opaque handle in case of success, NULL otherwise.
*/
atp_handle *atp_promote_current_thread_to_real_time(uint32_t audio_buffer_frames,
uint32_t audio_samplerate_hz);
/**
* Demotes the current thread promoted to real-time priority via
* `atp_demote_current_thread_from_real_time` to its previous priority.
*
* Returns 0 in case of success, non-zero otherwise.
*/
int32_t atp_demote_current_thread_from_real_time(atp_handle *handle);
/**
* Frees an atp_handle. This is useful when it impractical to call
*`atp_demote_current_thread_from_real_time` on the right thread. Access to the
* handle must be synchronized externaly (or the related thread must have
* exited).
*
* Returns 0 in case of success, non-zero otherwise.
*/
int32_t atp_free_handle(atp_handle *handle);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // AUDIO_THREAD_PRIORITY_H

View File

@ -0,0 +1,3 @@
#!/bin/sh
bindgen /usr/include/mach/thread_policy.h --no-layout-tests --whitelist-type "(thread_policy_flavor_t|thread_policy_t|thread_extended_policy_data_t|thread_time_constraint_policy_data_t|thread_precedence_policy_data_t|thread_t)" --whitelist-var "(THREAD_TIME_CONSTRAINT_POLICY|THREAD_EXTENDED_POLICY|THREAD_PRECEDENCE_POLICY)" > src/mach_sys.rs

View File

@ -0,0 +1,209 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#[macro_use]
extern crate cfg_if;
#[cfg(feature = "terminal-logging")]
extern crate simple_logger;
#[macro_use]
extern crate log;
cfg_if! {
if #[cfg(target_os = "macos")] {
mod rt_mach;
#[allow(unused, non_camel_case_types, non_snake_case, non_upper_case_globals)]
mod mach_sys;
extern crate mach;
extern crate libc;
use rt_mach::promote_current_thread_to_real_time_internal;
use rt_mach::demote_current_thread_from_real_time_internal;
use rt_mach::RtPriorityHandleInternal;
} else if #[cfg(target_os = "windows")] {
extern crate winapi;
mod rt_win;
use rt_win::promote_current_thread_to_real_time_internal;
use rt_win::demote_current_thread_from_real_time_internal;
use rt_win::RtPriorityHandleInternal;
} else if #[cfg(target_os = "linux")] {
mod rt_linux;
extern crate dbus;
extern crate libc;
use rt_linux::promote_current_thread_to_real_time_internal;
use rt_linux::demote_current_thread_from_real_time_internal;
use rt_linux::RtPriorityHandleInternal;
} else if #[cfg(target_os = "android")] {
pub struct RtPriorityHandleInternal {}
pub fn promote_current_thread_to_real_time_internal(_: u32, audio_samplerate_hz: u32) -> Result<RtPriorityHandle, ()> {
if audio_samplerate_hz == 0 {
return Err(());
}
// no-op
return Ok(RtPriorityHandle{});
}
pub fn demote_current_thread_from_real_time_internal(_: RtPriorityHandle) -> Result<(), ()> {
// no-op
return Ok(());
}
}
}
/// Opaque handle to a thread handle structure.
pub type RtPriorityHandle = RtPriorityHandleInternal;
/// Promote the calling thread thread to real-time priority.
///
/// # Arguments
///
/// * `audio_buffer_frames` - the exact or an upper limit on the number of frames that have to be
/// rendered each callback, or 0 for a sensible default value.
/// * `audio_samplerate_hz` - the sample-rate for this audio stream, in Hz.
///
/// # Return value
///
/// This function returns a `Result<RtPriorityHandle>`, which is an opaque struct to be passed to
/// `demote_current_thread_from_real_time` to revert to the previous thread priority.
pub fn promote_current_thread_to_real_time(
audio_buffer_frames: u32,
audio_samplerate_hz: u32,
) -> Result<RtPriorityHandle, ()> {
if audio_samplerate_hz == 0 {
return Err(());
}
return promote_current_thread_to_real_time_internal(audio_buffer_frames, audio_samplerate_hz);
}
/// Demotes the calling thread from real-time priority.
///
/// # Arguments
///
/// * `handle` - An opaque struct returned from a successful call to
/// `promote_current_thread_to_real_time`.
///
/// # Return value
///
/// `Ok` in scase of success, `Err` otherwise.
pub fn demote_current_thread_from_real_time(handle: RtPriorityHandle) -> Result<(), ()> {
return demote_current_thread_from_real_time_internal(handle);
}
/// Opaque handle for the C API
#[allow(non_camel_case_types)]
pub struct atp_handle(RtPriorityHandle);
/// Promote the calling thread thread to real-time priority, with a C API.
///
/// # Arguments
///
/// * `audio_buffer_frames` - the exact or an upper limit on the number of frames that have to be
/// rendered each callback, or 0 for a sensible default value.
/// * `audio_samplerate_hz` - the sample-rate for this audio stream, in Hz.
///
/// # Return value
///
/// This function returns `NULL` in case of error: if it couldn't bump the thread, or if the
/// `audio_samplerate_hz` is zero. It returns an opaque handle, to be passed to
/// `atp_demote_current_thread_from_real_time` to demote the thread.
///
/// Additionaly, NULL can be returned in sandboxed processes on Linux, when DBUS cannot be used in
/// the process (for example because the socket to DBUS cannot be created). If this is the case,
/// it's necessary to get the information from the thread to promote and ask another process to
/// promote it (maybe via another privileged process).
#[no_mangle]
pub extern "C" fn atp_promote_current_thread_to_real_time(
audio_buffer_frames: u32,
audio_samplerate_hz: u32,
) -> *mut atp_handle {
match promote_current_thread_to_real_time(audio_buffer_frames, audio_samplerate_hz) {
Ok(handle) => Box::into_raw(Box::new(atp_handle(handle))),
_ => std::ptr::null_mut(),
}
}
/// Demotes the calling thread from real-time priority, with a C API.
///
/// # Arguments
///
/// * `atp_handle` - An opaque struct returned from a successful call to
/// `atp_promote_current_thread_to_real_time`.
///
/// # Return value
///
/// 0 in case of success, non-zero in case of error.
#[no_mangle]
pub extern "C" fn atp_demote_current_thread_from_real_time(handle: *mut atp_handle) -> i32 {
assert!(!handle.is_null());
let handle = unsafe { Box::from_raw(handle) };
match demote_current_thread_from_real_time(handle.0) {
Ok(_) => 0,
_ => 1,
}
}
/// Frees a handle, with a C API.
///
/// This is useful when it impractical to call `atp_demote_current_thread_from_real_time` on the
/// right thread. Access to the handle must be synchronized externaly, or the thread that was
/// promoted to real-time priority must have exited.
///
/// # Arguments
///
/// * `atp_handle` - An opaque struct returned from a successful call to
/// `atp_promote_current_thread_to_real_time`.
///
/// # Return value
///
/// 0 in case of success, non-zero in case of error.
#[no_mangle]
pub extern "C" fn atp_free_handle(handle: *mut atp_handle) -> i32 {
if handle.is_null() {
return 1;
}
let _handle = unsafe { Box::from_raw(handle) };
0
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "terminal-logging")]
use simple_logger;
#[test]
fn it_works() {
#[cfg(feature = "terminal-logging")]
simple_logger::init().unwrap();
{
assert!(promote_current_thread_to_real_time(0, 0).is_err());
}
{
match promote_current_thread_to_real_time(0, 44100) {
Ok(rt_prio_handle) => {
demote_current_thread_from_real_time(rt_prio_handle).unwrap();
}
Err(e) => {
panic!(e);
}
}
}
{
match promote_current_thread_to_real_time(512, 44100) {
Ok(rt_prio_handle) => {
demote_current_thread_from_real_time(rt_prio_handle).unwrap();
}
Err(e) => {
panic!(e);
}
}
}
{
match promote_current_thread_to_real_time(512, 44100) {
Ok(_) => { }
Err(e) => {
panic!(e);
}
}
// automatically deallocated, but not demoted until the thread exits.
}
}
}

View File

@ -0,0 +1,36 @@
/* automatically generated by rust-bindgen */
pub const THREAD_EXTENDED_POLICY: u32 = 1;
pub const THREAD_TIME_CONSTRAINT_POLICY: u32 = 2;
pub const THREAD_PRECEDENCE_POLICY: u32 = 3;
pub type __darwin_natural_t = ::std::os::raw::c_uint;
pub type __darwin_mach_port_name_t = __darwin_natural_t;
pub type __darwin_mach_port_t = __darwin_mach_port_name_t;
pub type boolean_t = ::std::os::raw::c_uint;
pub type natural_t = __darwin_natural_t;
pub type integer_t = ::std::os::raw::c_int;
pub type mach_port_t = __darwin_mach_port_t;
pub type thread_t = mach_port_t;
pub type thread_policy_flavor_t = natural_t;
pub type thread_policy_t = *mut integer_t;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct thread_extended_policy {
pub timeshare: boolean_t,
}
pub type thread_extended_policy_data_t = thread_extended_policy;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct thread_time_constraint_policy {
pub period: u32,
pub computation: u32,
pub constraint: u32,
pub preemptible: boolean_t,
}
pub type thread_time_constraint_policy_data_t = thread_time_constraint_policy;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct thread_precedence_policy {
pub importance: integer_t,
}
pub type thread_precedence_policy_data_t = thread_precedence_policy;

View File

@ -0,0 +1,132 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Widely copied from dbus-rs/dbus/examples/rtkit.rs */
extern crate dbus;
extern crate libc;
use std::cmp;
use dbus::{Connection, BusType, Props, MessageItem, Message};
const DBUS_SOCKET_TIMEOUT: i32 = 10_000;
const RT_PRIO_DEFAULT: u32 = 10;
// This is different from libc::pid_t, which is 32 bits, and is defined in sys/types.h.
#[allow(non_camel_case_types)]
type kernel_pid_t = libc::c_long;
/*#[derive(Debug)]*/
pub struct RtPriorityHandleInternal {
/// Process-local thread id, used to restore scheduler characteristics.
pthread_id: libc::pthread_t,
/// The scheduler originaly associated with this thread (probably SCHED_OTHER).
policy: libc::c_int,
/// The initial priority for this thread.
param: libc::sched_param,
}
fn item_as_i64(i: MessageItem) -> Result<i64, Box<std::error::Error>> {
match i {
MessageItem::Int32(i) => Ok(i as i64),
MessageItem::Int64(i) => Ok(i),
_ => Err(Box::from(&*format!("Property is not integer ({:?})", i)))
}
}
fn rtkit_set_realtime(c: &Connection, thread: u64, prio: u32) -> Result<(), Box<std::error::Error>> {
let mut m = Message::new_method_call("org.freedesktop.RealtimeKit1",
"/org/freedesktop/RealtimeKit1",
"org.freedesktop.RealtimeKit1",
"MakeThreadRealtime")?;
m.append_items(&[thread.into(), prio.into()]);
c.send_with_reply_and_block(m, DBUS_SOCKET_TIMEOUT)?;
return Ok(());
}
fn make_realtime(tid: kernel_pid_t, max_slice_us: u64, prio: u32) -> Result<u32, Box<std::error::Error>> {
let c = Connection::get_private(BusType::System)?;
let p = Props::new(&c, "org.freedesktop.RealtimeKit1", "/org/freedesktop/RealtimeKit1",
"org.freedesktop.RealtimeKit1", DBUS_SOCKET_TIMEOUT);
// Make sure we don't fail by wanting too much
let max_prio = item_as_i64(p.get("MaxRealtimePriority")?)?;
if max_prio < 0 {
return Err(Box::from("invalid negative MaxRealtimePriority"));
}
let prio = cmp::min(prio, max_prio as u32);
// Enforce RLIMIT_RTPRIO, also a must before asking rtkit for rtprio
let max_rttime = item_as_i64(p.get("RTTimeUSecMax")?)?;
if max_rttime < 0 {
return Err(Box::from("invalid negative RTTimeUSecMax"));
}
// Only take what we need, or cap at the system limit, no further.
let rttime_request = cmp::min(max_slice_us, max_rttime as u64);
let new_limit = libc::rlimit64 { rlim_cur: rttime_request,
rlim_max: rttime_request };
let mut old_limit = new_limit;
if unsafe { libc::getrlimit64(libc::RLIMIT_RTTIME, &mut old_limit) } < 0 {
return Err(Box::from("getrlimit failed"));
}
if unsafe { libc::setrlimit64(libc::RLIMIT_RTTIME, &new_limit) } < 0 {
return Err(Box::from("setrlimit failed"));
}
// Finally, let's ask rtkit to make us realtime
let r = rtkit_set_realtime(&c, tid as u64, prio);
if r.is_err() {
unsafe { libc::setrlimit64(libc::RLIMIT_RTTIME, &old_limit) };
return Err(Box::from("could not set process as real-time."));
}
Ok(prio)
}
pub fn promote_current_thread_to_real_time_internal(audio_buffer_frames: u32,
audio_samplerate_hz: u32) -> Result<RtPriorityHandleInternal, ()>
{
let thread_id = unsafe { libc::syscall(libc::SYS_gettid) };
let pthread_id = unsafe { libc::pthread_self() };
let mut policy = 0;
let mut param = libc::sched_param { sched_priority: 0 };
if unsafe { libc::pthread_getschedparam(pthread_id, &mut policy, &mut param) } < 0 {
error!("pthread_getschedparam error {}", pthread_id);
return Err(());
}
let buffer_frames = if audio_buffer_frames > 0 {
audio_buffer_frames
} else {
// 50ms slice. This "ought to be enough for anybody".
audio_samplerate_hz / 20
};
let budget_us = (buffer_frames * 1_000_000 / audio_samplerate_hz) as u64;
let handle = RtPriorityHandleInternal { pthread_id, policy, param};
let r = make_realtime(thread_id, budget_us, RT_PRIO_DEFAULT);
if r.is_err() {
error!("Could not make thread real-time.");
return Err(());
}
return Ok(handle);
}
pub fn demote_current_thread_from_real_time_internal(rt_priority_handle: RtPriorityHandleInternal)
-> Result<(), ()> {
assert!(unsafe { libc::pthread_self() } == rt_priority_handle.pthread_id);
if unsafe { libc::pthread_setschedparam(rt_priority_handle.pthread_id,
rt_priority_handle.policy,
&rt_priority_handle.param) } < 0 {
error!("could not demote thread {}", rt_priority_handle.pthread_id);
return Err(());
}
return Ok(());
}

View File

@ -0,0 +1,149 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
use mach::kern_return::{kern_return_t, KERN_SUCCESS};
use mach::port::mach_port_t;
use mach::message::mach_msg_type_number_t;
use mach_sys::*;
use libc::{pthread_self, pthread_t, mach_timebase_info, mach_timebase_info_data_t};
use std::mem::size_of;
extern "C" {
fn pthread_mach_thread_np(tid: pthread_t) -> mach_port_t;
// Those functions are commented out in thread_policy.h but somehow it works just fine !?
fn thread_policy_set(thread: thread_t,
flavor: thread_policy_flavor_t,
policy_info: thread_policy_t,
count: mach_msg_type_number_t)
-> kern_return_t;
fn thread_policy_get(thread: thread_t,
flavor: thread_policy_flavor_t,
policy_info: thread_policy_t,
count: &mut mach_msg_type_number_t,
get_default: &mut boolean_t)
-> kern_return_t;
}
// can't use size_of in const fn just now in stable, use a macro for now.
macro_rules! THREAD_TIME_CONSTRAINT_POLICY_COUNT {
() => {
(size_of::<thread_time_constraint_policy_data_t>() / size_of::<integer_t>()) as u32;
}
}
#[derive(Debug)]
pub struct RtPriorityHandleInternal {
tid: mach_port_t,
previous_time_constraint_policy: thread_time_constraint_policy_data_t,
}
impl RtPriorityHandleInternal {
pub fn new() -> RtPriorityHandleInternal {
return RtPriorityHandleInternal {
tid: 0,
previous_time_constraint_policy: thread_time_constraint_policy_data_t {
period: 0,
computation: 0,
constraint: 0,
preemptible: 0
}
}
}
}
pub fn demote_current_thread_from_real_time_internal(rt_priority_handle: RtPriorityHandleInternal)
-> Result<(), ()> {
unsafe {
let rv: kern_return_t;
let mut h = rt_priority_handle;
rv = thread_policy_set(h.tid,
THREAD_TIME_CONSTRAINT_POLICY,
(&mut h.previous_time_constraint_policy) as *mut _ as
thread_policy_t,
THREAD_TIME_CONSTRAINT_POLICY_COUNT!());
if rv != KERN_SUCCESS as i32 {
error!("thread demotion error: thread_policy_set: RT");
return Err(());
}
info!("thread {} priority restored.", h.tid);
}
return Ok(());
}
pub fn promote_current_thread_to_real_time_internal(audio_buffer_frames: u32,
audio_samplerate_hz: u32)
-> Result<RtPriorityHandleInternal, ()> {
let mut rt_priority_handle = RtPriorityHandleInternal::new();
let buffer_frames = if audio_buffer_frames > 0 {
audio_buffer_frames
} else {
audio_samplerate_hz / 20
};
unsafe {
let tid: mach_port_t = pthread_mach_thread_np(pthread_self());
let mut rv: kern_return_t;
let mut time_constraints = thread_time_constraint_policy_data_t {
period: 0,
computation: 0,
constraint: 0,
preemptible: 0,
};
let mut count: mach_msg_type_number_t;
// Get current thread attributes, to revert back to the correct setting later if needed.
rt_priority_handle.tid = tid;
// false: we want to get the current value, not the default value. If this is `false` after
// returning, it means there are no current settings because of other factor, and the
// default was returned instead.
let mut get_default: boolean_t = 0;
count = THREAD_TIME_CONSTRAINT_POLICY_COUNT!();
rv = thread_policy_get(tid,
THREAD_TIME_CONSTRAINT_POLICY,
(&mut time_constraints) as *mut _ as thread_policy_t,
&mut count,
&mut get_default);
if rv != KERN_SUCCESS as i32 {
error!("thread promotion error: thread_policy_get: time_constraint");
return Err(());
}
rt_priority_handle.previous_time_constraint_policy = time_constraints;
let cb_duration = buffer_frames as f32 / (audio_samplerate_hz as f32) * 1000.;
// The multiplicators are somwhat arbitrary for now.
let mut timebase_info = mach_timebase_info_data_t { denom: 0, numer: 0 };
mach_timebase_info(&mut timebase_info);
let ms2abs: f32 = ((timebase_info.denom as f32) / timebase_info.numer as f32) * 1000000.;
time_constraints = thread_time_constraint_policy_data_t {
period: (cb_duration * ms2abs) as u32,
computation: (0.3 * ms2abs) as u32, // fixed 300us computation time
constraint: (cb_duration * ms2abs) as u32,
preemptible: 1, // true
};
rv = thread_policy_set(tid,
THREAD_TIME_CONSTRAINT_POLICY,
(&mut time_constraints) as *mut _ as thread_policy_t,
THREAD_TIME_CONSTRAINT_POLICY_COUNT!());
if rv != KERN_SUCCESS as i32 {
error!("thread promotion error: thread_policy_set: time_constraint");
return Err(());
}
info!("thread {} bumped to real time priority.", tid);
}
Ok(rt_priority_handle)
}

View File

@ -0,0 +1,57 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
use winapi::um::avrt::*;
use winapi::shared::ntdef::HANDLE;
use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi::GetLastError;
#[derive(Debug)]
pub struct RtPriorityHandleInternal {
mmcss_task_index: DWORD,
task_handle: HANDLE
}
impl RtPriorityHandleInternal {
pub fn new() -> RtPriorityHandleInternal {
return RtPriorityHandleInternal {
mmcss_task_index: 0 as DWORD,
task_handle: 0 as HANDLE
}
}
}
pub fn demote_current_thread_from_real_time_internal(rt_priority_handle: RtPriorityHandleInternal)
-> Result<(), ()> {
unsafe {
let rv = AvRevertMmThreadCharacteristics(rt_priority_handle.task_handle);
if rv == 0 {
error!("Unable to restore the thread priority ({})", GetLastError());
return Err(())
}
}
info!("task {} priority restored.", rt_priority_handle.mmcss_task_index);
return Ok(())
}
pub fn promote_current_thread_to_real_time_internal(_audio_buffer_frames: u32,
_audio_samplerate_hz: u32)
-> Result<RtPriorityHandleInternal, ()> {
let mut handle = RtPriorityHandleInternal::new();
unsafe {
handle.task_handle = AvSetMmThreadCharacteristicsA("Audio\0".as_ptr() as _, &mut handle.mmcss_task_index);
if handle.task_handle.is_null() {
error!("Unable to use mmcss to bump the thread priority ({})", GetLastError());
return Err(())
}
}
info!("task {} bumped to real time priority.", handle.mmcss_task_index);
Ok(handle)
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"b1f753282cb63124f9ee89da03b4aec27f948e18ff9fcfc9e7fac3ba19235061","LICENSE-APACHE":"453745410e3be8cf25d56872ea2aec975a78e6c9f217443d0bf908a5bce7c8ff","LICENSE-MIT":"de3911c2d98c8bd2d701ee721347053d9b55995a11f9a8c955e44d3ca1b376bf","examples/adv_server.rs":"45526c1ebeabad80e5dd5e8ecf071ea7a5e4870c58e47fad194f849fa347ef3a","examples/argument_guide.md":"b9824fc2b20c6478b3d42195f7d2486d11401aa9f72267e81ec3878bd6882e95","examples/client.rs":"56579c1a4fc3386ca41ddb350d9283d270e31cdf117fb815c84b6b0dd6548335","examples/properties.rs":"dac7eef86e17af1bc4b8d37f431686d3cc1f5890214ea880894c7cbd04ba2ad7","examples/properties_msgitem.rs":"b51e2cd87dc38696e8f0f98bac974d802ba00d69e0aff1102460fdfbf4448ffc","examples/rtkit.rs":"4365f0de2af7fe3c44e19688c8a2dafa4414aae0b21afc76b8fc09444b6da8e7","examples/server.rs":"9c286b26e45990cab5a7300bb5dd20048dd4dde6366d0e1cb6cdc85b7bf76eb6","examples/unity_focused_window.rs":"f1098e4ebce0feda47af862c6f3e755d6d74f78928731a75f15416bd76577fe1","src/arg/array_impl.rs":"bd18d93fe37a8053c0eb6e4e2d29cfc619adec69ba5ee3411cf03f6ad01fa0c0","src/arg/basic_impl.rs":"7c596da14de18220eb2258c80bc6eb0db9a7cd72bc85ba8d60da78cbf0232454","src/arg/mod.rs":"52f4cb60889e90a4ce628da13c0bce8f9f2505087ecb90b096ffa1bf1bc8c072","src/arg/msgarg.rs":"42b312d0780cb8e4c0cb9920e5850dcb99346dfb89c8df3b8ea9c12aa9bd78ff","src/arg/variantstruct_impl.rs":"d9ddc73c44f1e57b67a7a73e8204f6915b51365cd47b1caf68573eb802b93a01","src/connection.rs":"3d488c768ec4471f9dd8f487a1fb0eb7884c170e6f339f322ea9f7799b420e44","src/lib.rs":"da6df6814e39ac641d0b538330edbba01a140f3860e47c0cb1996799db40e900","src/message.rs":"714576a449bf37db9f0f12cb6aa1ef7c06412bad4dcd11e99f8ceb6dbe4a392b","src/methoddisp.rs":"57d5b0e7eef7b76393dfd80e2e5125b266521f3252edbc402b893f12791b933e","src/objpath.rs":"e9f662d6cc81ea0717553787773261e7fb3221b36fab1799fb281f21de961b72","src/prop.rs":"60541e569ff06f503d889a7b62dd0aa980d39be60cde01f917503a80e0b7b27f","src/signalargs.rs":"23fe8e2161f82e718fe7f65d249f082864767d13519dfba4af83f24887c8c8b3","src/stdintf.rs":"29027f8cffde7354fc432b306a3ade149bc12440f08fe86d1a72074d514d7101","src/strings.rs":"2234b35634c6ef7e0fb82d3ea59c8dd1a1147a1d47ba5d2f818046e4dd0625d3","src/tree/factory.rs":"77bfdfa9074e653b43e9c51b3e0b2dcfc9bc02948b7f9eb8e2fc0fe1a9009d14","src/tree/leaves.rs":"9c8b07925c07424a3977b8effa154e63d32addcbab1f59331025039592705bc1","src/tree/methodtype.rs":"6e77276ad1ca4040cd4bea320f525e49165e1d21df89281de4d9b1913129e0e2","src/tree/mod.rs":"471ff6e4bbd9c360326ed92867744b78235d769ba4483e0a8c20137153ab1e82","src/tree/objectpath.rs":"92e805ca9725aad04a600dff7441d275450762901e42a9ab1b71e70dd3746096","src/tree/utils.rs":"d15e64ed288ffa7477c2c35532d7f61feafb50ef6068606014101622bcd36caa","src/watch.rs":"04b4e1570492e944912a6d2048f2f44bc73919875b206fd4a80617b4e44650fe"},"package":"b9e1b39f3f6aa3d4a1522c4f0f9f1e9e9167bd93740a8690874caa7cf8ce47d7"}

38
third_party/rust/dbus/Cargo.toml vendored Normal file
View File

@ -0,0 +1,38 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "dbus"
version = "0.6.4"
authors = ["David Henningsson <diwic@ubuntu.com>"]
description = "Bindings to D-Bus, which is a bus commonly used on Linux for inter-process communication."
documentation = "http://docs.rs/dbus"
readme = "../README.md"
keywords = ["D-Bus", "DBus", "IPC"]
categories = ["os::unix-apis", "api-bindings"]
license = "Apache-2.0/MIT"
repository = "https://github.com/diwic/dbus-rs"
[dependencies.libc]
version = "0.2.7"
[dependencies.libdbus-sys]
version = "0.1.5"
[dev-dependencies.tempdir]
version = "0.3"
[features]
no-string-validation = []
[badges.is-it-maintained-issue-resolution]
repository = "diwic/dbus-rs"
[badges.is-it-maintained-open-issues]
repository = "diwic/dbus-rs"

202
third_party/rust/dbus/LICENSE-APACHE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014-2018 David Henningsson <diwic@ubuntu.com> and other contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

19
third_party/rust/dbus/LICENSE-MIT vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2014-2018 David Henningsson <diwic@ubuntu.com> and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,177 @@
// More advanced server example.
// This is supposed to look like a D-Bus service that allows the user to manipulate storage devices.
// Note: in the dbus-codegen/example directory, there is a version of this example where dbus-codegen
// was used to create some boilerplate code - feel free to compare the two examples.
extern crate dbus;
use std::sync::Arc;
use std::sync::mpsc;
use std::cell::Cell;
use std::thread;
use dbus::{Connection, BusType, tree, Path};
use dbus::tree::{Interface, Signal, MTFn, Access, MethodErr, EmitsChangedSignal};
// Our storage device
#[derive(Debug)]
struct Device {
description: String,
path: Path<'static>,
index: i32,
online: Cell<bool>,
checking: Cell<bool>,
}
// Every storage device has its own object path.
// We therefore create a link from the object path to the Device.
#[derive(Copy, Clone, Default, Debug)]
struct TData;
impl tree::DataType for TData {
type Tree = ();
type ObjectPath = Arc<Device>;
type Property = ();
type Interface = ();
type Method = ();
type Signal = ();
}
impl Device {
// Creates a "test" device (not a real one, since this is an example).
fn new_bogus(index: i32) -> Device {
Device {
description: format!("This is device {}, which is {}.", index,
["totally awesome", "really fancy", "still going strong"][(index as usize) % 3]),
path: format!("/Device{}", index).into(),
index: index,
online: Cell::new(index % 2 == 0),
checking: Cell::new(false),
}
}
}
// Here's where we implement the code for our interface.
fn create_iface(check_complete_s: mpsc::Sender<i32>) -> (Interface<MTFn<TData>, TData>, Arc<Signal<TData>>) {
let f = tree::Factory::new_fn();
let check_complete = Arc::new(f.signal("CheckComplete", ()));
(f.interface("com.example.dbus.rs.device", ())
// The online property can be both set and get
.add_p(f.property::<bool,_>("online", ())
.access(Access::ReadWrite)
.on_get(|i, m| {
let dev: &Arc<Device> = m.path.get_data();
i.append(dev.online.get());
Ok(())
})
.on_set(|i, m| {
let dev: &Arc<Device> = m.path.get_data();
let b: bool = try!(i.read());
if b && dev.checking.get() {
return Err(MethodErr::failed(&"Device currently under check, cannot bring online"))
}
dev.online.set(b);
Ok(())
})
)
// The "checking" property is read only
.add_p(f.property::<bool,_>("checking", ())
.emits_changed(EmitsChangedSignal::False)
.on_get(|i, m| {
let dev: &Arc<Device> = m.path.get_data();
i.append(dev.checking.get());
Ok(())
})
)
// ...and so is the "description" property
.add_p(f.property::<&str,_>("description", ())
.emits_changed(EmitsChangedSignal::Const)
.on_get(|i, m| {
let dev: &Arc<Device> = m.path.get_data();
i.append(&dev.description);
Ok(())
})
)
// ...add a method for starting a device check...
.add_m(f.method("check", (), move |m| {
let dev: &Arc<Device> = m.path.get_data();
if dev.checking.get() {
return Err(MethodErr::failed(&"Device currently under check, cannot start another check"))
}
if dev.online.get() {
return Err(MethodErr::failed(&"Device is currently online, cannot start check"))
}
dev.checking.set(true);
// Start some lengthy processing in a separate thread...
let devindex = dev.index;
let ch = check_complete_s.clone();
thread::spawn(move || {
// Bogus check of device
use std::time::Duration;
thread::sleep(Duration::from_secs(15));
// Tell main thread that we finished
ch.send(devindex).unwrap();
});
Ok(vec!(m.msg.method_return()))
}))
// Indicate that we send a special signal once checking has completed.
.add_s(check_complete.clone())
, check_complete)
}
fn create_tree(devices: &[Arc<Device>], iface: &Arc<Interface<MTFn<TData>, TData>>)
-> tree::Tree<MTFn<TData>, TData> {
let f = tree::Factory::new_fn();
let mut tree = f.tree(());
for dev in devices {
tree = tree.add(f.object_path(dev.path.clone(), dev.clone())
.introspectable()
.add(iface.clone())
);
}
tree
}
fn run() -> Result<(), Box<std::error::Error>> {
// Create our bogus devices
let devices: Vec<Arc<Device>> = (0..10).map(|i| Arc::new(Device::new_bogus(i))).collect();
// Create tree
let (check_complete_s, check_complete_r) = mpsc::channel::<i32>();
let (iface, sig) = create_iface(check_complete_s);
let tree = create_tree(&devices, &Arc::new(iface));
// Setup DBus connection
let c = try!(Connection::get_private(BusType::Session));
try!(c.register_name("com.example.dbus.rs.advancedserverexample", 0));
try!(tree.set_registered(&c, true));
// ...and serve incoming requests.
c.add_handler(tree);
loop {
// Wait for incoming messages. This will block up to one second.
// Discard the result - relevant messages have already been handled.
c.incoming(1000).next();
// Do all other things we need to do in our main loop.
if let Ok(idx) = check_complete_r.try_recv() {
let dev = &devices[idx as usize];
dev.checking.set(false);
try!(c.send(sig.msg(&dev.path, &"com.example.dbus.rs.device".into())).map_err(|_| "Sending DBus signal failed"));
}
}
}
fn main() {
if let Err(e) = run() {
println!("{}", e);
}
}

View File

@ -0,0 +1,193 @@
Preamble
--------
The different ways you can append and get message arguments can be a bit bewildering. I've iterated a few times on the design and didn't want to lose backwards compatibility.
This guide is to help you on your way. In addition, many of the examples in the examples directory append and read arguments.
Code generation
---------------
First - if you can get D-Bus introspection data, you can use the the `dbus-codegen` tool to generate some boilerplate code for you. E g, if you want to talk to NetworkManager:
```rust
cargo install dbus-codegen
dbus-codegen-rust -s -g -m None -d org.freedesktop.NetworkManager -p /org/freedesktop/NetworkManager > networkmanager.rs
```
You would then use this code like:
```rust
// main.rs
mod networkmanager;
/* ... */
// Start a connection to the system bus.
let c = Connection::get_private(BusType::System)?;
// Make a "ConnPath" struct that just contains a Connection, a destination and a path.
let p = c.with_path("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", 5000);
// Bring our generated code into scope.
use networkmanager::OrgFreedesktopNetworkManager;
// Now we can call methods on our connpath from the "org.freedesktop.NetworkManager" interface.
let devices = c.get_all_devices()?;
```
There is also pre-generated code for standard D-Bus interfaces in the `stdintf` module. A similar example:
```rust
let c = Connection::get_private(BusType::Session)?;
// Make a "ConnPath" struct that just contains a Connection, a destination and a path.
let p = c.with_path("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2", 5000);
// The ConnPath struct implements many traits, e g `org.freedesktop.DBus.Properties`. Bring the trait into scope.
use stdintf::org_freedesktop_dbus::Properties;
// Now we can call org.freedesktop.DBus.Properties.Get just like an ordinary method and get the result back.
let metadata = p.get("org.mpris.MediaPlayer2.Player", "Metadata")?;
```
For more details, see `dbus-codegen-rust --help` and the `README.md` in the dbus-codegen directory.
Now, if you want to make a service yourself, the generated code is more complex. And for some use cases, codegen isn't really an option, so let's move on:
Append / get basic types
------------------------
If you just want to get/append simple types, just use `append1` / `append2` / `append3`, and
`read1` / `read2` / `read3`. The imaginary method below takes one byte parameter and one string parameter, and returns one string parameter and one int parameter.
```rust
let m = Message::new_method_call(dest, path, intf, member)?.append2(5u8, "Foo");
let r = c.send_with_reply_and_block(m, 2000)?;
let (data1, data2): (&str, i32) = c.read2()?;
```
Arrays and dictionaries
-----------------------
D-Bus arrays and dictionaries usually correspond to `Vec` and `HashMap`. You can just append and get them like basic types:
```rust
let v = vec![3i32, 4i32, 5i32];
let mut map = HashMap::new();
map.insert("Funghi", 5u16);
map.insert("Mold", 8u16);
let m = Message::new_method_call(dest, path, intf, member)?.append2(v, map);
let r = c.send_with_reply_and_block(m, 2000)?;
let (data1, data2): (Vec<i32>, HashMap<&str, u16>) = r.read2()?;
```
Or combine them as you wish, e g, use a `Vec<Vec<u8>>`, a `HashMap<u64, Vec<String>>` or `HashMap<String, HashMap<String, i32>>` to construct more difficult types.
Slices can sometimes be used as arrays - e g, `&[&str]` can be appended, but only very simple types can be used with `get` and `read`, e g `&[u8]`.
This is the easiest way to get started, but in case you want to avoid the overhead of creating `Vec` or `HashMap`s, the "Array and Dict types" and "Iter / IterAppend" sections offer useful alternatives.
Variants
--------
Things are getting slightly more complex with Variants, because they are not strongly typed and thus not fit as well into Rust's strongly typed as arrays and dicts.
If you know the type beforehand, it's still easy:
```rust
let v = Variant("This is a variant containing a &str");
let m = Message::new_method_call(dest, path, intf, member)?.append1(v);
let r = c.send_with_reply_and_block(m, 2000)?;
let z: Variant<i32> = r.read1()?;
println!("Method returned {}", z.0);
```
The `Variant` struct is just a wrapper with a public interior, so you can easily both read from it and write to it with the `.0` accessor.
Sometimes you don't know the type beforehand. We can solve this in two ways (choose whichever is more appropriate for your use case), either through the trait object `Box<RefArg>` or through `Iter` / `IterAppend` (see later sections).
Through trait objects:
```rust
let x = Box::new(5000i32) as Box<RefArg>;
let m = Message::new_method_call(dest, path, intf, member)?.append1(Variant(x));
let r = c.send_with_reply_and_block(m, 2000)?;
let z: Variant<Box<RefArg>> = r.read1()?;
```
Ok, so we retrieved our `Box<RefArg>`. We now need to use the `RefArg` methods to probe it, to see what's inside. Easiest is to use `as_i64` or `as_str` if you want to test for integer or string types. Use `as_iter` if the variant contains a complex type you need to iterate over.
For floating point values, use `arg::cast` (this requires that the RefArg is `static` though, due to Rust type system limitations).
Match over `arg_type` if you need to know the exact type.
```rust
let z: Variant<Box<RefArg + 'static>> = r.read1()?;
let value = &z.0;
if let Some(s) = value.as_str() { println!("It's a string: {}", s); }
else if let Some(i) = value.as_i64() { println!("It's an integer: {}", i); }
else if let Some(f) = arg::cast::<f64>(value) { println!("It's a float: {}", f); }
else { println!("Don't know how to handle a {:?}", value.arg_type()) }
```
Dicts and variants are sometimes combined, e g, you might need to read a D-Bus dictionary of String to Variants. You can then read these as `HashMap<String, Variant<Box<RefArg>>>`.
Structs
-------
D-Bus structs are implemented as Rust tuples. You can append and get tuples like you do with other types of arguments.
TODO: Example
Declare method arguments
------------------------
When you make a `Tree`, you want to declare what input and output arguments your method expects - so that correct D-Bus introspection data can be generated. You'll use the same types as you learned earlier in this guide:
```rust
factory.method( /* ... */ )
.inarg::<HashMap<i32, Vec<(i32, bool, String)>>,_>("request")
.outarg::<&str,_>("reply")
```
The types are just for generating a correct signature, they are never instantiated. Many different types can generate the same signature - e g, `Array<u8, _>`, `Vec<u8>` and `&[u8]` will all generate the same signature. `Variant` will generate the same type signature regardless of what's inside, so just write `Variant<()>` for simplicity.
Iter / IterAppend
-----------------
Iter and IterAppend are more low-level, direct methods to get and append arguments. They can, e g, come handy if you have more than five arguments to read.
E g, for appending a variant with IterAppend you can use `IterAppend::new(&msg).append_variant(|i| i.append(5000i32))` to append what you need to your variant inside the closure.
To read a variant you can use `let i = msg.read1::<Variant<Iter>>::()?` and then examine the methods on `i.0` to probe the variant.
Array and Dict types
--------------------
These provide slightly better flexibility than using `Vec` and `HashMap` by instead integrating with `Iterator`. Here's an example where you can append and get a dictionary without having to create a HashMap:
```rust
let x = &[("Hello", true), ("World", false)];
let m = Message::new_method_call(dest, path, intf, member)?.append1(Dict::new(x));
let r = c.send_with_reply_and_block(m, 2000)?;
let z: Dict<i32, &str, _> = r.read1()?;
for (key, value) in z { /* do something */ }
```
An edge case where this is necessary is having floating point keys in a dictionary - this is supported in D-Bus but not in Rust's `HashMap`. I have never seen this in practice, though.
Unusual types
-------------
The types `Path`, `Signature` and `OwnedFd` are not often used, but they can be appended and read as other argument types. `Path` and `Signature` will return strings with a borrowed lifetime - use `.into_static()` if you want to untie that lifetime.
For `OwnedFd`, which a wrapper around a file descriptor, remember that the file descriptor will be closed when it goes out of scope.
MessageItem
-----------
MessageItem was the first design - an enum representing a D-Bus argument. It still works, but I doubt you'll ever need to use it. Newer methods provide better type safety, speed, and ergonomics.

View File

@ -0,0 +1,14 @@
extern crate dbus;
use dbus::{Connection, BusType, Message};
use dbus::arg::Array;
fn main() {
let c = Connection::get_private(BusType::Session).unwrap();
let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
let r = c.send_with_reply_and_block(m, 2000).unwrap();
// ListNames returns one argument, which is an array of strings.
let arr: Array<&str, _> = r.get1().unwrap();
for name in arr { println!("{}", name); }
}

View File

@ -0,0 +1,50 @@
extern crate dbus;
use dbus::{Connection, BusType, stdintf, arg};
use std::collections::HashMap;
fn print_refarg(value: &arg::RefArg) {
// We don't know what type the value is. We'll try a few and fall back to
// debug printing if the value is more complex than that.
if let Some(s) = value.as_str() { println!("{}", s); }
else if let Some(i) = value.as_i64() { println!("{}", i); }
else { println!("{:?}", value); }
}
fn main() {
// Connect to server and create a ConnPath. A ConnPath implements several interfaces,
// in this case we'll use OrgFreedesktopDBusProperties, which allows us to call "get".
let c = Connection::get_private(BusType::Session).unwrap();
let p = c.with_path("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2", 5000);
use stdintf::org_freedesktop_dbus::Properties;
// The Metadata property is a Dict<String, Variant>.
// Option 1: we can get the dict straight into a hashmap, like this:
let metadata: HashMap<String, arg::Variant<Box<arg::RefArg>>> = p.get("org.mpris.MediaPlayer2.Player", "Metadata").unwrap();
println!("Option 1:");
// We now iterate over the hashmap.
for (key, value) in metadata.iter() {
print!(" {}: ", key);
print_refarg(&value);
}
// Option 2: we can get the entire dict as a RefArg and get the values out by iterating over it.
let metadata: Box<arg::RefArg> = p.get("org.mpris.MediaPlayer2.Player", "Metadata").unwrap();
// When using "as_iter()" for a dict, we'll get one key, it's value, next key, it's value, etc.
let mut iter = metadata.as_iter().unwrap();
println!("Option 2:");
while let Some(key) = iter.next() {
// Printing the key is easy, since we know it's a String.
print!(" {}: ", key.as_str().unwrap());
let value = iter.next().unwrap();
print_refarg(&value);
}
}

View File

@ -0,0 +1,10 @@
extern crate dbus;
use dbus::{Connection, BusType, Props};
fn main() {
let c = Connection::get_private(BusType::System).unwrap();
let p = Props::new(&c, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority",
"org.freedesktop.PolicyKit1.Authority", 10000);
println!("BackendVersion: {:?}", p.get("BackendVersion").unwrap())
}

91
third_party/rust/dbus/examples/rtkit.rs vendored Normal file
View File

@ -0,0 +1,91 @@
/* This example asks the rtkit service to make our thread realtime priority.
Rtkit puts a few limitations on us to let us become realtime, such as setting
RLIMIT_RTTIME correctly, hence the syscalls. */
extern crate dbus;
extern crate libc;
use std::cmp;
use libc::c_int;
use dbus::{Connection, BusType, Props, MessageItem, Message};
/* External C stuff. Currently only working for x86_64 */
#[allow(non_upper_case_globals)]
#[cfg(target_arch = "x86_64")]
static SYS_gettid: c_int = 186;
static RLIMIT_RTTIME: c_int = 15;
#[repr(C)]
#[cfg(target_arch = "x86_64")]
#[derive(Copy, Clone)]
struct rlimit {
rlim_cur: u64,
rlim_max: u64,
}
extern "C" {
fn syscall(num: c_int, ...) -> c_int;
fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int;
fn setrlimit(resource: c_int, rlim: *const rlimit) -> c_int;
}
fn item_as_i64(i: MessageItem) -> Result<i64, Box<std::error::Error>> {
match i {
MessageItem::Int32(i) => Ok(i as i64),
MessageItem::Int64(i) => Ok(i),
_ => Err(Box::from(&*format!("Property is not integer ({:?})", i)))
}
}
fn rtkit_set_realtime(c: &Connection, thread: u64, prio: u32) -> Result<(), ::dbus::Error> {
let mut m = Message::new_method_call("org.freedesktop.RealtimeKit1", "/org/freedesktop/RealtimeKit1",
"org.freedesktop.RealtimeKit1", "MakeThreadRealtime").unwrap();
m.append_items(&[thread.into(), prio.into()]);
let mut r = try!(c.send_with_reply_and_block(m, 10000));
r.as_result().map(|_| ())
}
fn make_realtime(prio: u32) -> Result<u32, Box<std::error::Error>> {
let c = try!(Connection::get_private(BusType::System));
let p = Props::new(&c, "org.freedesktop.RealtimeKit1", "/org/freedesktop/RealtimeKit1",
"org.freedesktop.RealtimeKit1", 10000);
// Make sure we don't fail by wanting too much
let max_prio = try!(item_as_i64(try!(p.get("MaxRealtimePriority")))) as u32;
let prio = cmp::min(prio, max_prio);
// Enforce RLIMIT_RTPRIO, also a must before asking rtkit for rtprio
let max_rttime = try!(item_as_i64(try!(p.get("RTTimeNSecMax")))) as u64;
let new_limit = rlimit { rlim_cur: max_rttime, rlim_max: max_rttime };
let mut old_limit = new_limit;
if unsafe { getrlimit(RLIMIT_RTTIME, &mut old_limit) } < 0 {
return Err(Box::from("getrlimit failed"));
}
if unsafe { setrlimit(RLIMIT_RTTIME, &new_limit) } < 0 {
return Err(Box::from("setrlimit failed"));
}
// Finally, let's ask rtkit to make us realtime
let thread_id = unsafe { syscall(SYS_gettid) };
let r = rtkit_set_realtime(&c, thread_id as u64, prio);
if r.is_err() {
unsafe { setrlimit(RLIMIT_RTTIME, &old_limit) };
}
try!(r);
Ok(prio)
}
fn main() {
match make_realtime(5) {
Ok(n) => println!("Got rtprio, level {}", n),
Err(e) => println!("No rtprio: {}", e),
}
}

View File

@ -0,0 +1,72 @@
/* This example creates a D-Bus server with the following functionality:
It registers the "com.example.dbustest" name, creates a "/hello" object path,
which has an "com.example.dbustest" interface.
The interface has a "Hello" method (which takes no arguments and returns a string),
and a "HelloHappened" signal (with a string argument) which is sent every time
someone calls the "Hello" method.
*/
extern crate dbus;
use std::sync::Arc;
use dbus::{Connection, BusType, NameFlag};
use dbus::tree::Factory;
fn main() {
// Let's start by starting up a connection to the session bus and register a name.
let c = Connection::get_private(BusType::Session).unwrap();
c.register_name("com.example.dbustest", NameFlag::ReplaceExisting as u32).unwrap();
// The choice of factory tells us what type of tree we want,
// and if we want any extra data inside. We pick the simplest variant.
let f = Factory::new_fn::<()>();
// We create the signal first, since we'll need it in both inside the method callback
// and when creating the tree.
let signal = Arc::new(f.signal("HelloHappened", ()).sarg::<&str,_>("sender"));
let signal2 = signal.clone();
// We create a tree with one object path inside and make that path introspectable.
let tree = f.tree(()).add(f.object_path("/hello", ()).introspectable().add(
// We add an interface to the object path...
f.interface("com.example.dbustest", ()).add_m(
// ...and a method inside the interface.
f.method("Hello", (), move |m| {
// This is the callback that will be called when another peer on the bus calls our method.
// the callback receives "MethodInfo" struct and can return either an error, or a list of
// messages to send back.
let name: &str = m.msg.read1()?;
let s = format!("Hello {}!", name);
let mret = m.msg.method_return().append1(s);
let sig = signal.msg(m.path.get_name(), m.iface.get_name())
.append1(&*name);
// Two messages will be returned - one is the method return (and should always be there),
// and in our case we also have a signal we want to send at the same time.
Ok(vec!(mret, sig))
// Our method has one output argument and one input argument.
}).outarg::<&str,_>("reply")
.inarg::<&str,_>("name")
// We also add the signal to the interface. This is mainly for introspection.
).add_s(signal2)
));
// We register all object paths in the tree.
tree.set_registered(&c, true).unwrap();
// We add the tree to the connection so that incoming method calls will be handled
// automatically during calls to "incoming".
c.add_handler(tree);
// Serve other peers forever.
loop { c.incoming(1000).next(); }
}

View File

@ -0,0 +1,25 @@
extern crate dbus;
// Tracks currently focused window under the Unity desktop by listening to the
// FocusedWindowChanged signal. The signal contains "window_id", "app_id" and "stage",
// we print only "app_id".
use dbus::{Connection, BusType, ConnectionItem};
fn focus_msg(ci: &ConnectionItem) -> Option<&str> {
let m = if let &ConnectionItem::Signal(ref s) = ci { s } else { return None };
if &*m.interface().unwrap() != "com.canonical.Unity.WindowStack" { return None };
if &*m.member().unwrap() != "FocusedWindowChanged" { return None };
let (_, app) = m.get2::<u32, &str>();
app
}
fn main() {
let c = Connection::get_private(BusType::Session).unwrap();
c.add_match("interface='com.canonical.Unity.WindowStack',member='FocusedWindowChanged'").unwrap();
for i in c.iter(1000) {
if let Some(app) = focus_msg(&i) { println!("{} has now focus.", app) };
}
}

View File

@ -0,0 +1,483 @@
use super::*;
use {Signature, Path, Message, ffi, OwnedFd};
use std::marker::PhantomData;
use std::{ptr, mem, any, fmt};
use super::check;
use std::ffi::{CString};
use std::os::raw::{c_void, c_int};
use std::collections::HashMap;
use std::hash::Hash;
// Map DBus-Type -> Alignment. Copied from _dbus_marshal_write_fixed_multi in
// http://dbus.freedesktop.org/doc/api/html/dbus-marshal-basic_8c_source.html#l01020
// Note that Rust booleans are one byte, dbus booleans are four bytes!
const FIXED_ARRAY_ALIGNMENTS: [(ArgType, usize); 9] = [
(ArgType::Byte, 1),
(ArgType::Int16, 2),
(ArgType::UInt16, 2),
(ArgType::UInt32, 4),
(ArgType::Int32, 4),
(ArgType::Boolean, 4),
(ArgType::Int64, 8),
(ArgType::UInt64, 8),
(ArgType::Double, 8)
];
/// Represents a D-Bus array.
impl<'a, T: Arg> Arg for &'a [T] {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) }
}
fn array_append<T: Arg, F: FnMut(&T, &mut IterAppend)>(z: &[T], i: &mut IterAppend, mut f: F) {
let zptr = z.as_ptr();
let zlen = z.len() as i32;
// Can we do append_fixed_array?
let a = (T::ARG_TYPE, mem::size_of::<T>());
let can_fixed_array = (zlen > 1) && (z.len() == zlen as usize) && FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == a);
i.append_container(ArgType::Array, Some(T::signature().as_cstr()), |s|
if can_fixed_array { unsafe { check("dbus_message_iter_append_fixed_array",
ffi::dbus_message_iter_append_fixed_array(&mut s.0, a.0 as c_int, &zptr as *const _ as *const c_void, zlen)) }}
else { for arg in z { f(arg, s); }}
);
}
/// Appends a D-Bus array. Note: In case you have a large array of a type that implements FixedArray,
/// using this method will be more efficient than using an Array.
impl<'a, T: Arg + Append + Clone> Append for &'a [T] {
fn append(self, i: &mut IterAppend) {
array_append(self, i, |arg, s| arg.clone().append(s));
}
}
impl<'a, T: Arg + RefArg> RefArg for &'a [T] {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) }
fn append(&self, i: &mut IterAppend) {
array_append(self, i, |arg, s| (arg as &RefArg).append(s));
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalArray {
inner_sig: <T as Arg>::signature(),
data: self.iter().map(|x| x.box_clone()).collect(),
})
}
}
impl<T: Arg + RefArg> RefArg for Vec<T> {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) }
fn append(&self, i: &mut IterAppend) {
array_append(&self, i, |arg, s| (arg as &RefArg).append(s));
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> {
Some(Box::new(self.iter().map(|b| b as &RefArg)))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() }
}
impl<'a, T: FixedArray> Get<'a> for &'a [T] {
fn get(i: &mut Iter<'a>) -> Option<&'a [T]> {
debug_assert!(FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == (T::ARG_TYPE, mem::size_of::<T>())));
i.recurse(Self::ARG_TYPE).and_then(|mut si| unsafe {
let etype = ffi::dbus_message_iter_get_element_type(&mut i.0);
if etype != T::ARG_TYPE as c_int { return None };
let mut v = ptr::null_mut();
let mut i = 0;
ffi::dbus_message_iter_get_fixed_array(&mut si.0, &mut v as *mut _ as *mut c_void, &mut i);
if v == ptr::null_mut() {
assert_eq!(i, 0);
Some(&[][..])
} else {
Some(::std::slice::from_raw_parts(v, i as usize))
}
})
}
}
#[derive(Copy, Clone, Debug)]
/// Append a D-Bus dict type (i e, an array of dict entries).
///
/// See the argument guide and module level documentation for details and alternatives.
pub struct Dict<'a, K: DictKey, V: Arg, I>(I, PhantomData<(&'a Message, *const K, *const V)>);
impl<'a, K: DictKey, V: Arg, I> Dict<'a, K, V, I> {
fn entry_sig() -> String { format!("{{{}{}}}", K::signature(), V::signature()) }
}
impl<'a, K: 'a + DictKey, V: 'a + Append + Arg, I: Iterator<Item=(K, V)>> Dict<'a, K, V, I> {
/// Creates a new Dict from an iterator. The iterator is consumed when appended.
pub fn new<J: IntoIterator<IntoIter=I, Item=(K, V)>>(j: J) -> Dict<'a, K, V, I> { Dict(j.into_iter(), PhantomData) }
}
impl<'a, K: DictKey, V: Arg, I> Arg for Dict<'a, K, V, I> {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> Signature<'static> {
Signature::from(format!("a{}", Self::entry_sig())) }
}
impl<'a, K: 'a + DictKey + Append, V: 'a + Append + Arg, I: Iterator<Item=(K, V)>> Append for Dict<'a, K, V, I> {
fn append(self, i: &mut IterAppend) {
let z = self.0;
i.append_container(Self::ARG_TYPE, Some(&CString::new(Self::entry_sig()).unwrap()), |s| for (k, v) in z {
s.append_container(ArgType::DictEntry, None, |ss| {
k.append(ss);
v.append(ss);
})
});
}
}
impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Get<'a> for Dict<'a, K, V, Iter<'a>> {
fn get(i: &mut Iter<'a>) -> Option<Self> {
i.recurse(Self::ARG_TYPE).map(|si| Dict(si, PhantomData))
// TODO: Verify full element signature?
}
}
impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Iterator for Dict<'a, K, V, Iter<'a>> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
let i = self.0.recurse(ArgType::DictEntry).and_then(|mut si| {
let k = si.get();
if k.is_none() { return None };
assert!(si.next());
let v = si.get();
if v.is_none() { return None };
Some((k.unwrap(), v.unwrap()))
});
self.0.next();
i
}
}
impl<K: DictKey, V: Arg> Arg for HashMap<K, V> {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> Signature<'static> {
Signature::from(format!("a{{{}{}}}", K::signature(), V::signature())) }
}
impl<K: DictKey + Append + Eq + Hash, V: Arg + Append> Append for HashMap<K, V> {
fn append(self, i: &mut IterAppend) {
Dict::new(self.into_iter()).append(i);
}
}
impl<'a, K: DictKey + Get<'a> + Eq + Hash, V: Arg + Get<'a>> Get<'a> for HashMap<K, V> {
fn get(i: &mut Iter<'a>) -> Option<Self> {
// TODO: Full element signature is not verified.
Dict::get(i).map(|d| d.into_iter().collect())
}
}
impl<K: DictKey + RefArg + Eq + Hash, V: RefArg + Arg> RefArg for HashMap<K, V> {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { format!("a{{{}{}}}", <K as Arg>::signature(), <V as Arg>::signature()).into() }
fn append(&self, i: &mut IterAppend) {
let sig = CString::new(format!("{{{}{}}}", <K as Arg>::signature(), <V as Arg>::signature())).unwrap();
i.append_container(ArgType::Array, Some(&sig), |s| for (k, v) in self {
s.append_container(ArgType::DictEntry, None, |ss| {
k.append(ss);
v.append(ss);
})
});
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> {
Some(Box::new(self.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter())))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalDict {
outer_sig: self.signature(),
data: self.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(),
})
}
}
impl<T: Arg> Arg for Vec<T> {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) }
}
impl<T: Arg + Append> Append for Vec<T> {
fn append(self, i: &mut IterAppend) {
Array::new(self).append(i);
}
}
impl<'a, T: Arg + Get<'a>> Get<'a> for Vec<T> {
fn get(i: &mut Iter<'a>) -> Option<Self> {
<Array<T, Iter<'a>>>::get(i).map(|a| a.collect())
}
}
#[derive(Copy, Clone, Debug)]
/// Represents a D-Bus Array. Maximum flexibility (wraps an iterator of items to append).
///
/// See the argument guide and module level documentation for details and alternatives.
pub struct Array<'a, T, I>(I, PhantomData<(*const T, &'a Message)>);
impl<'a, T: 'a, I: Iterator<Item=T>> Array<'a, T, I> {
/// Creates a new Array from an iterator. The iterator is consumed when appending.
pub fn new<J: IntoIterator<IntoIter=I, Item=T>>(j: J) -> Array<'a, T, I> { Array(j.into_iter(), PhantomData) }
}
impl<'a, T: Arg, I> Arg for Array<'a, T, I> {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) }
}
impl<'a, T: 'a + Arg + Append, I: Iterator<Item=T>> Append for Array<'a, T, I> {
fn append(self, i: &mut IterAppend) {
let z = self.0;
i.append_container(ArgType::Array, Some(T::signature().as_cstr()), |s| for arg in z { arg.append(s) });
}
}
impl<'a, T: Arg + Get<'a>> Get<'a> for Array<'a, T, Iter<'a>> {
fn get(i: &mut Iter<'a>) -> Option<Array<'a, T, Iter<'a>>> {
i.recurse(Self::ARG_TYPE).map(|si| Array(si, PhantomData))
// TODO: Verify full element signature?
}
}
impl<'a, T: Get<'a>> Iterator for Array<'a, T, Iter<'a>> {
type Item = T;
fn next(&mut self) -> Option<T> {
let i = self.0.get();
self.0.next();
i
}
}
// Due to the strong typing here; RefArg is implemented only for T's that are both Arg and RefArg.
// We need Arg for this to work for empty arrays (we can't get signature from first element if there is no elements).
// We need RefArg for non-consuming append.
impl<'a, T: 'a + Arg + fmt::Debug + RefArg, I: fmt::Debug + Clone + Iterator<Item=&'a T>> RefArg for Array<'static, T, I> {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) }
fn append(&self, i: &mut IterAppend) {
let z = self.0.clone();
i.append_container(ArgType::Array, Some(<T as Arg>::signature().as_cstr()), |s|
for arg in z { (arg as &RefArg).append(s) }
);
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalArray {
inner_sig: <T as Arg>::signature(),
data: self.0.clone().map(|x| x.box_clone()).collect(),
})
}
}
fn get_fixed_array_refarg<'a, T: FixedArray + Clone + RefArg>(i: &mut Iter<'a>) -> Box<RefArg> {
let s = <&[T]>::get(i).unwrap();
Box::new(s.to_vec())
}
fn get_var_array_refarg<'a, T: 'static + RefArg + Arg, F: FnMut(&mut Iter<'a>) -> Option<T>>
(i: &mut Iter<'a>, mut f: F) -> Box<RefArg> {
let mut v: Vec<T> = vec!(); // dbus_message_iter_get_element_count might be O(n), better not use it
let mut si = i.recurse(ArgType::Array).unwrap();
while let Some(q) = f(&mut si) { v.push(q); si.next(); }
Box::new(v)
}
#[derive(Debug)]
struct InternalDict<K> {
data: Vec<(K, Box<RefArg>)>,
outer_sig: Signature<'static>,
}
fn get_dict_refarg<'a, K, F: FnMut(&mut Iter<'a>) -> Option<K>>(i: &mut Iter<'a>, mut f: F) -> Box<RefArg>
where K: DictKey + 'static + RefArg + Clone
{
let mut data = vec!();
let outer_sig = i.signature();
let mut si = i.recurse(ArgType::Array).unwrap();
while let Some(mut d) = si.recurse(ArgType::DictEntry) {
let k = f(&mut d).unwrap();
d.next();
data.push((k, d.get_refarg().unwrap()));
si.next();
}
Box::new(InternalDict { data, outer_sig })
}
// This only happens from box_clone
impl RefArg for InternalDict<Box<RefArg>> {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { self.outer_sig.clone() }
fn append(&self, i: &mut IterAppend) {
let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..];
let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap();
i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data {
s.append_container(ArgType::DictEntry, None, |ss| {
k.append(ss);
v.append(ss);
})
});
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> {
Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter())))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalDict {
data: self.data.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(),
outer_sig: self.outer_sig.clone(),
})
}
}
impl<K: DictKey + RefArg + Clone + 'static> RefArg for InternalDict<K> {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { self.outer_sig.clone() }
fn append(&self, i: &mut IterAppend) {
let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..];
let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap();
i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data {
s.append_container(ArgType::DictEntry, None, |ss| {
k.append(ss);
v.append(ss);
})
});
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> {
Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter())))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalDict {
data: self.data.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(),
outer_sig: self.outer_sig.clone(),
})
}
}
// Fallback for Arrays of Arrays and Arrays of Structs.
// We store the signature manually here and promise that it is correct for all elements
// has that signature.
#[derive(Debug)]
struct InternalArray {
data: Vec<Box<RefArg>>,
inner_sig: Signature<'static>,
}
fn get_internal_array<'a>(i: &mut Iter<'a>) -> Box<RefArg> {
let mut si = i.recurse(ArgType::Array).unwrap();
let inner_sig = si.signature();
let data = si.collect::<Vec<_>>();
Box::new(InternalArray { data, inner_sig })
}
impl RefArg for InternalArray {
fn arg_type(&self) -> ArgType { ArgType::Array }
fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", self.inner_sig)) }
fn append(&self, i: &mut IterAppend) {
i.append_container(ArgType::Array, Some(self.inner_sig.as_cstr()), |s|
for arg in &self.data { (arg as &RefArg).append(s) }
);
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> {
Some(Box::new(self.data.iter().map(|b| b as &RefArg)))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
Box::new(InternalArray {
data: self.data.iter().map(|x| x.box_clone()).collect(),
inner_sig: self.inner_sig.clone(),
})
}
}
pub fn get_array_refarg<'a>(i: &mut Iter<'a>) -> Box<RefArg> {
debug_assert!(i.arg_type() == ArgType::Array);
let etype = ArgType::from_i32(unsafe { ffi::dbus_message_iter_get_element_type(&mut i.0) } as i32).unwrap();
let x = match etype {
ArgType::Byte => get_fixed_array_refarg::<u8>(i),
ArgType::Int16 => get_fixed_array_refarg::<i16>(i),
ArgType::UInt16 => get_fixed_array_refarg::<u16>(i),
ArgType::Int32 => get_fixed_array_refarg::<i32>(i),
ArgType::UInt32 => get_fixed_array_refarg::<u32>(i),
ArgType::Int64 => get_fixed_array_refarg::<i64>(i),
ArgType::UInt64 => get_fixed_array_refarg::<u64>(i),
ArgType::Double => get_fixed_array_refarg::<f64>(i),
ArgType::String => get_var_array_refarg::<String, _>(i, |si| si.get()),
ArgType::ObjectPath => get_var_array_refarg::<Path<'static>, _>(i, |si| si.get::<Path>().map(|s| s.into_static())),
ArgType::Signature => get_var_array_refarg::<Signature<'static>, _>(i, |si| si.get::<Signature>().map(|s| s.into_static())),
ArgType::Variant => get_var_array_refarg::<Variant<Box<RefArg>>, _>(i, |si| Variant::new_refarg(si)),
ArgType::Boolean => get_var_array_refarg::<bool, _>(i, |si| si.get()),
ArgType::Invalid => panic!("Array with Invalid ArgType"),
ArgType::Array => get_internal_array(i),
ArgType::DictEntry => {
let key = ArgType::from_i32(i.signature().as_bytes()[2] as i32).unwrap(); // The third character, after "a{", is our key.
match key {
ArgType::Byte => get_dict_refarg::<u8, _>(i, |si| si.get()),
ArgType::Int16 => get_dict_refarg::<i16, _>(i, |si| si.get()),
ArgType::UInt16 => get_dict_refarg::<u16, _>(i, |si| si.get()),
ArgType::Int32 => get_dict_refarg::<i32, _>(i, |si| si.get()),
ArgType::UInt32 => get_dict_refarg::<u32, _>(i, |si| si.get()),
ArgType::Int64 => get_dict_refarg::<i64, _>(i, |si| si.get()),
ArgType::UInt64 => get_dict_refarg::<u64, _>(i, |si| si.get()),
ArgType::Double => get_dict_refarg::<f64, _>(i, |si| si.get()),
ArgType::Boolean => get_dict_refarg::<bool, _>(i, |si| si.get()),
// ArgType::UnixFd => get_dict_refarg::<OwnedFd, _>(i, |si| si.get()),
ArgType::String => get_dict_refarg::<String, _>(i, |si| si.get()),
ArgType::ObjectPath => get_dict_refarg::<Path<'static>, _>(i, |si| si.get::<Path>().map(|s| s.into_static())),
ArgType::Signature => get_dict_refarg::<Signature<'static>, _>(i, |si| si.get::<Signature>().map(|s| s.into_static())),
_ => panic!("Array with invalid dictkey ({:?})", key),
}
}
ArgType::UnixFd => get_var_array_refarg::<OwnedFd, _>(i, |si| si.get()),
ArgType::Struct => get_internal_array(i),
};
debug_assert_eq!(i.signature(), x.signature());
x
}

View File

@ -0,0 +1,308 @@
use ffi;
use super::*;
use super::check;
use {Signature, Path, OwnedFd};
use std::{ptr, any, mem};
use std::ffi::CStr;
use std::os::raw::{c_void, c_char, c_int};
fn arg_append_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: T) {
let p = &v as *const _ as *const c_void;
unsafe {
check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, p));
};
}
fn arg_get_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<T> {
unsafe {
let mut c: T = mem::zeroed();
if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None };
ffi::dbus_message_iter_get_basic(i, &mut c as *mut _ as *mut c_void);
Some(c)
}
}
fn arg_append_f64(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: f64) {
let p = &v as *const _ as *const c_void;
unsafe {
check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, p));
};
}
fn arg_get_f64(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<f64> {
let mut c = 0f64;
unsafe {
if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None };
ffi::dbus_message_iter_get_basic(i, &mut c as *mut _ as *mut c_void);
}
Some(c)
}
fn arg_append_str(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: &CStr) {
let p = v.as_ptr();
let q = &p as *const _ as *const c_void;
unsafe {
check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, q));
};
}
unsafe fn arg_get_str<'a>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<&'a CStr> {
if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None };
let mut p = ptr::null_mut();
ffi::dbus_message_iter_get_basic(i, &mut p as *mut _ as *mut c_void);
Some(CStr::from_ptr(p as *const c_char))
}
// Implementation for basic types.
macro_rules! integer_impl {
($t: ident, $s: ident, $f: expr, $i: ident, $ii: expr, $u: ident, $uu: expr, $fff: ident, $ff: expr) => {
impl Arg for $t {
const ARG_TYPE: ArgType = ArgType::$s;
#[inline]
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } }
}
impl Append for $t {
fn append(self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, self) }
}
impl<'a> Get<'a> for $t {
fn get(i: &mut Iter) -> Option<Self> { arg_get_basic(&mut i.0, ArgType::$s) }
}
impl RefArg for $t {
#[inline]
fn arg_type(&self) -> ArgType { ArgType::$s }
#[inline]
fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } }
#[inline]
fn append(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, *self) }
#[inline]
fn as_any(&self) -> &any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any { self }
#[inline]
fn as_i64(&self) -> Option<i64> { let $i = *self; $ii }
#[inline]
fn as_u64(&self) -> Option<u64> { let $u = *self; $uu }
#[inline]
fn as_f64(&self) -> Option<f64> { let $fff = *self; $ff }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) }
}
impl DictKey for $t {}
unsafe impl FixedArray for $t {}
}} // End of macro_rules
integer_impl!(u8, Byte, b"y\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64));
integer_impl!(i16, Int16, b"n\0", i, Some(i as i64), _u, None, f, Some(f as f64));
integer_impl!(u16, UInt16, b"q\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64));
integer_impl!(i32, Int32, b"i\0", i, Some(i as i64), _u, None, f, Some(f as f64));
integer_impl!(u32, UInt32, b"u\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64));
integer_impl!(i64, Int64, b"x\0", i, Some(i), _u, None, _f, None);
integer_impl!(u64, UInt64, b"t\0", _i, None, u, Some(u as u64), _f, None);
macro_rules! refarg_impl {
($t: ty, $i: ident, $ii: expr, $ss: expr, $uu: expr, $ff: expr) => {
impl RefArg for $t {
#[inline]
fn arg_type(&self) -> ArgType { <$t as Arg>::ARG_TYPE }
#[inline]
fn signature(&self) -> Signature<'static> { <$t as Arg>::signature() }
#[inline]
fn append(&self, i: &mut IterAppend) { <$t as Append>::append(self.clone(), i) }
#[inline]
fn as_any(&self) -> &any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any { self }
#[inline]
fn as_i64(&self) -> Option<i64> { let $i = self; $ii }
#[inline]
fn as_u64(&self) -> Option<u64> { let $i = self; $uu }
#[inline]
fn as_f64(&self) -> Option<f64> { let $i = self; $ff }
#[inline]
fn as_str(&self) -> Option<&str> { let $i = self; $ss }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) }
}
}
}
impl Arg for bool {
const ARG_TYPE: ArgType = ArgType::Boolean;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"b\0") } }
}
impl Append for bool {
fn append(self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::Boolean, if self {1} else {0}) }
}
impl DictKey for bool {}
impl<'a> Get<'a> for bool {
fn get(i: &mut Iter) -> Option<Self> { arg_get_basic::<u32>(&mut i.0, ArgType::Boolean).map(|q| q != 0) }
}
refarg_impl!(bool, _i, Some(if *_i { 1 } else { 0 }), None, Some(if *_i { 1 as u64 } else { 0 as u64 }), Some(if *_i { 1 as f64 } else { 0 as f64 }));
impl Arg for f64 {
const ARG_TYPE: ArgType = ArgType::Double;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"d\0") } }
}
impl Append for f64 {
fn append(self, i: &mut IterAppend) { arg_append_f64(&mut i.0, ArgType::Double, self) }
}
impl DictKey for f64 {}
impl<'a> Get<'a> for f64 {
fn get(i: &mut Iter) -> Option<Self> { arg_get_f64(&mut i.0, ArgType::Double) }
}
unsafe impl FixedArray for f64 {}
refarg_impl!(f64, _i, None, None, None, Some(*_i));
/// Represents a D-Bus string.
impl<'a> Arg for &'a str {
const ARG_TYPE: ArgType = ArgType::String;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } }
}
impl<'a> Append for &'a str {
fn append(self, i: &mut IterAppend) {
use std::borrow::Cow;
let b: &[u8] = self.as_bytes();
let v: Cow<[u8]> = if b.len() > 0 && b[b.len()-1] == 0 { Cow::Borrowed(b) }
else {
let mut bb: Vec<u8> = b.into();
bb.push(0);
Cow::Owned(bb)
};
let z = unsafe { CStr::from_ptr(v.as_ptr() as *const c_char) };
arg_append_str(&mut i.0, ArgType::String, &z)
}
}
impl<'a> DictKey for &'a str {}
impl<'a> Get<'a> for &'a str {
fn get(i: &mut Iter<'a>) -> Option<&'a str> { unsafe { arg_get_str(&mut i.0, ArgType::String) }
.and_then(|s| s.to_str().ok()) }
}
impl<'a> Arg for String {
const ARG_TYPE: ArgType = ArgType::String;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } }
}
impl<'a> Append for String {
fn append(mut self, i: &mut IterAppend) {
self.push_str("\0");
let s: &str = &self;
s.append(i)
}
}
impl<'a> DictKey for String {}
impl<'a> Get<'a> for String {
fn get(i: &mut Iter<'a>) -> Option<String> { <&str>::get(i).map(|s| String::from(s)) }
}
refarg_impl!(String, _i, None, Some(&_i), None, None);
/// Represents a D-Bus string.
impl<'a> Arg for &'a CStr {
const ARG_TYPE: ArgType = ArgType::String;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } }
}
/*
/// Note: Will give D-Bus errors in case the CStr is not valid UTF-8.
impl<'a> Append for &'a CStr {
fn append(self, i: &mut IterAppend) {
arg_append_str(&mut i.0, Self::arg_type(), &self)
}
}
*/
impl<'a> DictKey for &'a CStr {}
impl<'a> Get<'a> for &'a CStr {
fn get(i: &mut Iter<'a>) -> Option<&'a CStr> { unsafe { arg_get_str(&mut i.0, Self::ARG_TYPE) }}
}
impl Arg for OwnedFd {
const ARG_TYPE: ArgType = ArgType::UnixFd;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"h\0") } }
}
impl Append for OwnedFd {
fn append(self, i: &mut IterAppend) {
use std::os::unix::io::AsRawFd;
arg_append_basic(&mut i.0, ArgType::UnixFd, self.as_raw_fd())
}
}
impl DictKey for OwnedFd {}
impl<'a> Get<'a> for OwnedFd {
fn get(i: &mut Iter) -> Option<Self> {
arg_get_basic(&mut i.0, ArgType::UnixFd).map(|q| OwnedFd::new(q))
}
}
refarg_impl!(OwnedFd, _i, { use std::os::unix::io::AsRawFd; Some(_i.as_raw_fd() as i64) }, None, None, None);
macro_rules! string_impl {
($t: ident, $s: ident, $f: expr) => {
impl<'a> Arg for $t<'a> {
const ARG_TYPE: ArgType = ArgType::$s;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } }
}
impl RefArg for $t<'static> {
fn arg_type(&self) -> ArgType { ArgType::$s }
fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } }
fn append(&self, i: &mut IterAppend) { arg_append_str(&mut i.0, ArgType::$s, self.as_cstr()) }
#[inline]
fn as_any(&self) -> &any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any { self }
#[inline]
fn as_str(&self) -> Option<&str> { Some(self) }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone().into_static()) }
}
impl<'a> DictKey for $t<'a> {}
impl<'a> Append for $t<'a> {
fn append(self, i: &mut IterAppend) {
arg_append_str(&mut i.0, ArgType::$s, self.as_cstr())
}
}
/*
Unfortunately, this does not work because it conflicts with getting a $t<'static>.
impl<'a> Get<'a> for $t<'a> {
fn get(i: &mut Iter<'a>) -> Option<$t<'a>> { unsafe { arg_get_str(&mut i.0, ArgType::$s) }
.map(|s| unsafe { $t::from_slice_unchecked(s.to_bytes_with_nul()) } ) }
}
*/
impl<'a> Get<'a> for $t<'static> {
fn get(i: &mut Iter<'a>) -> Option<$t<'static>> { unsafe {
arg_get_str(&mut i.0, ArgType::$s).map(|s| $t::from_slice_unchecked(s.to_bytes_with_nul()).into_static())
}}
}
}
}
string_impl!(Path, ObjectPath, b"o\0");
string_impl!(Signature, Signature, b"g\0");

440
third_party/rust/dbus/src/arg/mod.rs vendored Normal file
View File

@ -0,0 +1,440 @@
//! Types and traits for easily getting a message's arguments, or appening a message with arguments.
//!
//! Also see the arguments guide (in the examples directory).
//!
//! A message has `read1`, `read2` etc, and `append1`, `append2` etc, which is your
//! starting point into this module's types.
//!
//! **Append a**:
//!
//! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type
//!
//! `&str` - a D-Bus string. D-Bus strings do not allow null characters, so
//! if the string contains null characters, it will be cropped
//! to only include the data before the null character. (Tip: This allows for skipping an
//! allocation by writing a string literal which ends with a null character.)
//!
//! `&[T] where T: Append` - a D-Bus array. Note: can use an efficient fast-path in case of
//! T being an FixedArray type.
//!
//! `Array<T, I> where T: Append, I: Iterator<Item=T>` - a D-Bus array, maximum flexibility.
//!
//! `Variant<T> where T: Append` - a D-Bus variant.
//!
//! `(T1, T2) where T1: Append, T2: Append` - tuples are D-Bus structs. Implemented up to 12.
//!
//! `Dict<K, V, I> where K: Append + DictKey, V: Append, I: Iterator<Item=(&K, &V)>` - A D-Bus dict (array of dict entries).
//!
//! `Path` - a D-Bus object path.
//!
//! `Signature` - a D-Bus signature.
//!
//! `OwnedFd` - shares the file descriptor with the remote side.
//!
//! **Get / read a**:
//!
//! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type
//!
//! `&str`, `&CStr` - a D-Bus string. D-Bus strings are always UTF-8 and do not contain null characters.
//!
//! `&[T] where T: FixedArray` - a D-Bus array of integers or f64.
//!
//! `Array<T, Iter> where T: Get` - a D-Bus array, maximum flexibility. Implements Iterator so you can easily
//! collect it into, e g, a `Vec`.
//!
//! `Variant<T> where T: Get` - a D-Bus variant. Use this type of Variant if you know the inner type.
//!
//! `Variant<Iter>` - a D-Bus variant. This type of Variant allows you to examine the inner type.
//!
//! `(T1, T2) where T1: Get, T2: Get` - tuples are D-Bus structs. Implemented up to 12.
//!
//! `Dict<K, V, Iter> where K: Get + DictKey, V: Get` - A D-Bus dict (array of dict entries). Implements Iterator so you can easily
//! collect it into, e g, a `HashMap`.
//!
//! `Path` - a D-Bus object path.
//!
//! `Signature` - a D-Bus signature.
//!
//! `OwnedFd` - a file descriptor sent from the remote side.
//!
mod msgarg;
mod basic_impl;
mod variantstruct_impl;
mod array_impl;
pub use self::msgarg::{Arg, FixedArray, Get, DictKey, Append, RefArg, cast, cast_mut};
pub use self::array_impl::{Array, Dict};
pub use self::variantstruct_impl::Variant;
use std::{fmt, mem, ptr, error};
use {ffi, Message, message, Signature, Path, OwnedFd};
use std::ffi::{CStr, CString};
use std::os::raw::{c_void, c_int};
fn check(f: &str, i: u32) { if i == 0 { panic!("D-Bus error: '{}' failed", f) }}
fn ffi_iter() -> ffi::DBusMessageIter { unsafe { mem::zeroed() }}
#[derive(Clone, Copy)]
/// Helper struct for appending one or more arguments to a Message.
pub struct IterAppend<'a>(ffi::DBusMessageIter, &'a Message);
impl<'a> IterAppend<'a> {
/// Creates a new IterAppend struct.
pub fn new(m: &'a mut Message) -> IterAppend<'a> {
let mut i = ffi_iter();
unsafe { ffi::dbus_message_iter_init_append(message::get_message_ptr(m), &mut i) };
IterAppend(i, m)
}
/// Appends the argument.
pub fn append<T: Append>(&mut self, a: T) { a.append(self) }
fn append_container<F: FnOnce(&mut IterAppend<'a>)>(&mut self, arg_type: ArgType, sig: Option<&CStr>, f: F) {
let mut s = IterAppend(ffi_iter(), self.1);
let p = sig.map(|s| s.as_ptr()).unwrap_or(ptr::null());
check("dbus_message_iter_open_container",
unsafe { ffi::dbus_message_iter_open_container(&mut self.0, arg_type as c_int, p, &mut s.0) });
f(&mut s);
check("dbus_message_iter_close_container",
unsafe { ffi::dbus_message_iter_close_container(&mut self.0, &mut s.0) });
}
/// Low-level function to append a variant.
///
/// Use in case the `Variant` struct is not flexible enough -
/// the easier way is to just call e g "append1" on a message and supply a `Variant` parameter.
///
/// In order not to get D-Bus errors: during the call to "f" you need to call "append" on
/// the supplied `IterAppend` exactly once,
/// and with a value which has the same signature as inner_sig.
pub fn append_variant<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) {
self.append_container(ArgType::Variant, Some(inner_sig.as_cstr()), f)
}
/// Low-level function to append an array.
///
/// Use in case the `Array` struct is not flexible enough -
/// the easier way is to just call e g "append1" on a message and supply an `Array` parameter.
///
/// In order not to get D-Bus errors: during the call to "f", you should only call "append" on
/// the supplied `IterAppend` with values which has the same signature as inner_sig.
pub fn append_array<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) {
self.append_container(ArgType::Array, Some(inner_sig.as_cstr()), f)
}
/// Low-level function to append a struct.
///
/// Use in case tuples are not flexible enough -
/// the easier way is to just call e g "append1" on a message and supply a tuple parameter.
pub fn append_struct<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) {
self.append_container(ArgType::Struct, None, f)
}
/// Low-level function to append a dict entry.
///
/// Use in case the `Dict` struct is not flexible enough -
/// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter.
///
/// In order not to get D-Bus errors: during the call to "f", you should call "append" once
/// for the key, then once for the value. You should only call this function for a subiterator
/// you got from calling "append_dict", and signatures need to match what you specified in "append_dict".
pub fn append_dict_entry<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) {
self.append_container(ArgType::DictEntry, None, f)
}
/// Low-level function to append a dict.
///
/// Use in case the `Dict` struct is not flexible enough -
/// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter.
///
/// In order not to get D-Bus errors: during the call to "f", you should only call "append_dict_entry"
/// for the subiterator - do this as many times as the number of dict entries.
pub fn append_dict<F: FnOnce(&mut IterAppend<'a>)>(&mut self, key_sig: &Signature, value_sig: &Signature, f: F) {
let sig = format!("{{{}{}}}", key_sig, value_sig);
self.append_container(Array::<bool,()>::ARG_TYPE, Some(&CString::new(sig).unwrap()), f);
}
}
#[derive(Clone, Copy)]
/// Helper struct for retrieve one or more arguments from a Message.
pub struct Iter<'a>(ffi::DBusMessageIter, &'a Message, u32);
impl<'a> Iter<'a> {
/// Creates a new struct for iterating over the arguments of a message, starting with the first argument.
pub fn new(m: &'a Message) -> Iter<'a> {
let mut i = ffi_iter();
unsafe { ffi::dbus_message_iter_init(message::get_message_ptr(m), &mut i) };
Iter(i, m, 0)
}
/// Returns the current argument, if T is the argument type. Otherwise returns None.
pub fn get<T: Get<'a>>(&mut self) -> Option<T> {
T::get(self)
}
/// Returns the current argument as a trait object (experimental).
///
/// Note: For the more complex arguments (arrays / dicts / structs, and especially
/// combinations thereof), their internal representations are still a bit in flux.
/// Instead, use as_iter() to read the values of those.
///
/// The rest are unlikely to change - Variants are `Variant<Box<RefArg>>`, strings are `String`,
/// paths are `Path<'static>`, signatures are `Signature<'static>`, Int32 are `i32s` and so on.
pub fn get_refarg(&mut self) -> Option<Box<RefArg + 'static>> {
Some(match self.arg_type() {
ArgType::Array => array_impl::get_array_refarg(self),
ArgType::Variant => Box::new(Variant::new_refarg(self).unwrap()),
ArgType::Boolean => Box::new(self.get::<bool>().unwrap()),
ArgType::Invalid => return None,
ArgType::String => Box::new(self.get::<String>().unwrap()),
ArgType::DictEntry => unimplemented!(),
ArgType::Byte => Box::new(self.get::<u8>().unwrap()),
ArgType::Int16 => Box::new(self.get::<i16>().unwrap()),
ArgType::UInt16 => Box::new(self.get::<u16>().unwrap()),
ArgType::Int32 => Box::new(self.get::<i32>().unwrap()),
ArgType::UInt32 => Box::new(self.get::<u32>().unwrap()),
ArgType::Int64 => Box::new(self.get::<i64>().unwrap()),
ArgType::UInt64 => Box::new(self.get::<u64>().unwrap()),
ArgType::Double => Box::new(self.get::<f64>().unwrap()),
ArgType::UnixFd => Box::new(self.get::<OwnedFd>().unwrap()),
ArgType::Struct => Box::new(self.recurse(ArgType::Struct).unwrap().collect::<Vec<_>>()),
ArgType::ObjectPath => Box::new(self.get::<Path>().unwrap().into_static()),
ArgType::Signature => Box::new(self.get::<Signature>().unwrap().into_static()),
})
}
/// Returns the type signature for the current argument.
pub fn signature(&mut self) -> Signature<'static> {
unsafe {
let c = ffi::dbus_message_iter_get_signature(&mut self.0);
assert!(c != ptr::null_mut());
let cc = CStr::from_ptr(c);
let r = Signature::new(cc.to_bytes());
ffi::dbus_free(c as *mut c_void);
r.unwrap()
}
}
/// The raw arg_type for the current item.
///
/// Unlike Arg::arg_type, this requires access to self and is not a static method.
/// You can match this against Arg::arg_type for different types to understand what type the current item is.
/// In case you're past the last argument, this function will return 0.
pub fn arg_type(&mut self) -> ArgType {
let s = unsafe { ffi::dbus_message_iter_get_arg_type(&mut self.0) };
ArgType::from_i32(s as i32).unwrap()
}
/// Returns false if there are no more items.
pub fn next(&mut self) -> bool {
self.2 += 1;
unsafe { ffi::dbus_message_iter_next(&mut self.0) != 0 }
}
/// Wrapper around `get` and `next`. Calls `get`, and then `next` if `get` succeeded.
///
/// Also returns a `Result` rather than an `Option` to work better with `try!`.
///
/// # Example
/// ```ignore
/// struct ServiceBrowserItemNew {
/// interface: i32,
/// protocol: i32,
/// name: String,
/// item_type: String,
/// domain: String,
/// flags: u32,
/// }
///
/// fn service_browser_item_new_msg(m: &Message) -> Result<ServiceBrowserItemNew, TypeMismatchError> {
/// let mut iter = m.iter_init();
/// Ok(ServiceBrowserItemNew {
/// interface: try!(iter.read()),
/// protocol: try!(iter.read()),
/// name: try!(iter.read()),
/// item_type: try!(iter.read()),
/// domain: try!(iter.read()),
/// flags: try!(iter.read()),
/// })
/// }
/// ```
pub fn read<T: Arg + Get<'a>>(&mut self) -> Result<T, TypeMismatchError> {
let r = try!(self.get().ok_or_else(||
TypeMismatchError { expected: T::ARG_TYPE, found: self.arg_type(), position: self.2 }));
self.next();
Ok(r)
}
/// If the current argument is a container of the specified arg_type, then a new
/// Iter is returned which is for iterating over the contents inside the container.
///
/// Primarily for internal use (the "get" function is more ergonomic), but could be
/// useful for recursing into containers with unknown types.
pub fn recurse(&mut self, arg_type: ArgType) -> Option<Iter<'a>> {
let containers = [ArgType::Array, ArgType::DictEntry, ArgType::Struct, ArgType::Variant];
if !containers.iter().any(|&t| t == arg_type) { return None; }
let mut subiter = ffi_iter();
unsafe {
if ffi::dbus_message_iter_get_arg_type(&mut self.0) != arg_type as c_int { return None };
ffi::dbus_message_iter_recurse(&mut self.0, &mut subiter)
}
Some(Iter(subiter, self.1, 0))
}
}
impl<'a> fmt::Debug for Iter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut z = self.clone();
let mut t = f.debug_tuple("Iter");
loop {
t.field(&z.arg_type());
if !z.next() { break }
}
t.finish()
}
}
impl<'a> Iterator for Iter<'a> {
type Item = Box<RefArg + 'static>;
fn next(&mut self) -> Option<Self::Item> {
let r = self.get_refarg();
if r.is_some() { self.next(); }
r
}
}
/// Type of Argument
///
/// use this to figure out, e g, which type of argument is at the current position of Iter.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum ArgType {
/// Dicts are Arrays of dict entries, so Dict types will have Array as ArgType.
Array = ffi::DBUS_TYPE_ARRAY as u8,
/// Variant
Variant = ffi::DBUS_TYPE_VARIANT as u8,
/// bool
Boolean = ffi::DBUS_TYPE_BOOLEAN as u8,
/// Invalid arg type - this is also the ArgType returned when there are no more arguments available.
Invalid = ffi::DBUS_TYPE_INVALID as u8,
/// String
String = ffi::DBUS_TYPE_STRING as u8,
/// Dict entry; you'll usually not encounter this one as dicts are arrays of dict entries.
DictEntry = ffi::DBUS_TYPE_DICT_ENTRY as u8,
/// u8
Byte = ffi::DBUS_TYPE_BYTE as u8,
/// i16
Int16 = ffi::DBUS_TYPE_INT16 as u8,
/// u16
UInt16 = ffi::DBUS_TYPE_UINT16 as u8,
/// i32
Int32 = ffi::DBUS_TYPE_INT32 as u8,
/// u32
UInt32 = ffi::DBUS_TYPE_UINT32 as u8,
/// i64
Int64 = ffi::DBUS_TYPE_INT64 as u8,
/// u64
UInt64 = ffi::DBUS_TYPE_UINT64 as u8,
/// f64
Double = ffi::DBUS_TYPE_DOUBLE as u8,
/// OwnedFd
UnixFd = ffi::DBUS_TYPE_UNIX_FD as u8,
/// Use tuples or Vec<Box<RefArg>> to read/write structs.
Struct = ffi::DBUS_TYPE_STRUCT as u8,
/// Path
ObjectPath = ffi::DBUS_TYPE_OBJECT_PATH as u8,
/// Signature
Signature = ffi::DBUS_TYPE_SIGNATURE as u8,
}
const ALL_ARG_TYPES: [(ArgType, &'static str); 18] =
[(ArgType::Variant, "Variant"),
(ArgType::Array, "Array/Dict"),
(ArgType::Struct, "Struct"),
(ArgType::String, "String"),
(ArgType::DictEntry, "Dict entry"),
(ArgType::ObjectPath, "Path"),
(ArgType::Signature, "Signature"),
(ArgType::UnixFd, "OwnedFd"),
(ArgType::Boolean, "bool"),
(ArgType::Byte, "u8"),
(ArgType::Int16, "i16"),
(ArgType::Int32, "i32"),
(ArgType::Int64, "i64"),
(ArgType::UInt16, "u16"),
(ArgType::UInt32, "u32"),
(ArgType::UInt64, "u64"),
(ArgType::Double, "f64"),
(ArgType::Invalid, "nothing")];
impl ArgType {
/// A str corresponding to the name of a Rust type.
pub fn as_str(self) -> &'static str {
ALL_ARG_TYPES.iter().skip_while(|a| a.0 != self).next().unwrap().1
}
/// Converts an i32 to an ArgType (or an error).
pub fn from_i32(i: i32) -> Result<ArgType, String> {
for &(a, _) in &ALL_ARG_TYPES {
if a as i32 == i { return Ok(a); }
}
Err(format!("Invalid ArgType {} ({})", i, i as u8 as char))
}
}
/// Error struct to indicate a D-Bus argument type mismatch.
///
/// Might be returned from `iter::read()`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TypeMismatchError {
expected: ArgType,
found: ArgType,
position: u32,
}
impl TypeMismatchError {
/// The ArgType we were trying to read, but failed
pub fn expected_arg_type(&self) -> ArgType { self.expected }
/// The ArgType we should have been trying to read, if we wanted the read to succeed
pub fn found_arg_type(&self) -> ArgType { self.found }
/// At what argument was the error found?
///
/// Returns 0 for first argument, 1 for second argument, etc.
pub fn pos(&self) -> u32 { self.position }
}
impl error::Error for TypeMismatchError {
fn description(&self) -> &str { "D-Bus argument type mismatch" }
fn cause(&self) -> Option<&error::Error> { None }
}
impl fmt::Display for TypeMismatchError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} at position {}: expected {}, found {}",
(self as &error::Error).description(),
self.position, self.expected.as_str(),
if self.expected == self.found { "same but still different somehow" } else { self.found.as_str() }
)
}
}
#[allow(dead_code)]
fn test_compile() {
let mut q = IterAppend::new(unsafe { mem::transmute(0usize) });
q.append(5u8);
q.append(Array::new(&[5u8, 6, 7]));
q.append((8u8, &[9u8, 6, 7][..]));
q.append(Variant((6u8, 7u8)));
}

336
third_party/rust/dbus/src/arg/msgarg.rs vendored Normal file
View File

@ -0,0 +1,336 @@
#![allow(dead_code)]
use {Signature};
use std::{fmt, any};
use std::sync::Arc;
use std::rc::Rc;
use super::{Iter, IterAppend, ArgType};
/// Types that can represent a D-Bus message argument implement this trait.
///
/// Types should also implement either Append or Get to be useful.
pub trait Arg {
/// The corresponding D-Bus argument type code.
const ARG_TYPE: ArgType;
/// The corresponding D-Bus argument type code; just returns ARG_TYPE.
///
/// For backwards compatibility.
#[deprecated(note = "Use associated constant ARG_TYPE instead")]
fn arg_type() -> ArgType { return Self::ARG_TYPE; }
/// The corresponding D-Bus type signature for this type.
fn signature() -> Signature<'static>;
}
/// Types that can be appended to a message as arguments implement this trait.
pub trait Append: Sized {
/// Performs the append operation.
fn append(self, &mut IterAppend);
}
/// Types that can be retrieved from a message as arguments implement this trait.
pub trait Get<'a>: Sized {
/// Performs the get operation.
fn get(i: &mut Iter<'a>) -> Option<Self>;
}
/// Object safe version of Arg + Append + Get.
pub trait RefArg: fmt::Debug {
/// The corresponding D-Bus argument type code.
fn arg_type(&self) -> ArgType;
/// The corresponding D-Bus type signature for this type.
fn signature(&self) -> Signature<'static>;
/// Performs the append operation.
fn append(&self, &mut IterAppend);
/// Transforms this argument to Any (which can be downcasted to read the current value).
///
/// Note: The internal representation of complex types (Array, Dict, Struct) is unstable
/// and as_any should not be relied upon for these types. Use as_iter instead.
fn as_any(&self) -> &any::Any where Self: 'static;
/// Transforms this argument to Any (which can be downcasted to read the current value).
///
/// Note: The internal representation of complex types (Array, Dict, Struct) is unstable
/// and as_any should not be relied upon for these types. Use as_iter instead.
///
/// # Panic
/// Will panic if the interior cannot be made mutable, e g, if encapsulated
/// inside a Rc with a reference count > 1.
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static;
/// Try to read the argument as an i64.
///
/// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Int64, UnixFd.
#[inline]
fn as_i64(&self) -> Option<i64> { None }
/// Try to read the argument as an u64.
///
/// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, UInt64.
#[inline]
fn as_u64(&self) -> Option<u64> { None }
/// Try to read the argument as an f64.
///
/// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Double.
#[inline]
fn as_f64(&self) -> Option<f64> { None }
/// Try to read the argument as a str.
///
/// Works for: String, ObjectPath, Signature.
#[inline]
fn as_str(&self) -> Option<&str> { None }
/// Try to read the argument as an iterator.
///
/// Works for: Array/Dict, Struct, Variant.
#[inline]
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { None }
/// Deep clone of the RefArg, causing the result to be 'static.
///
/// Usable as an escape hatch in case of lifetime problems with RefArg.
///
/// In case of complex types (Array, Dict, Struct), the clone is not guaranteed
/// to have the same internal representation as the original.
fn box_clone(&self) -> Box<RefArg + 'static> { unimplemented!() /* Needed for backwards comp */ }
}
impl<'a> Get<'a> for Box<RefArg> {
fn get(i: &mut Iter<'a>) -> Option<Self> { i.get_refarg() }
}
/// Cast a RefArg as a specific type (shortcut for any + downcast)
#[inline]
pub fn cast<'a, T: 'static>(a: &'a (RefArg + 'static)) -> Option<&'a T> { a.as_any().downcast_ref() }
/// Cast a RefArg as a specific type (shortcut for any_mut + downcast_mut)
///
/// # Panic
/// Will panic if the interior cannot be made mutable, e g, if encapsulated
/// inside a Rc with a reference count > 1.
#[inline]
pub fn cast_mut<'a, T: 'static>(a: &'a mut (RefArg + 'static)) -> Option<&'a mut T> { a.as_any_mut().downcast_mut() }
/// If a type implements this trait, it means the size and alignment is the same
/// as in D-Bus. This means that you can quickly append and get slices of this type.
///
/// Note: Booleans do not implement this trait because D-Bus booleans are 4 bytes and Rust booleans are 1 byte.
pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {}
/// Types that can be used as keys in a dict type implement this trait.
pub trait DictKey: Arg {}
/// Simple lift over reference to value - this makes some iterators more ergonomic to use
impl<'a, T: Arg> Arg for &'a T {
const ARG_TYPE: ArgType = T::ARG_TYPE;
fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Append + Clone> Append for &'a T {
fn append(self, i: &mut IterAppend) { self.clone().append(i) }
}
impl<'a, T: DictKey> DictKey for &'a T {}
impl<'a, T: RefArg + ?Sized> RefArg for &'a T {
#[inline]
fn arg_type(&self) -> ArgType { (&**self).arg_type() }
#[inline]
fn signature(&self) -> Signature<'static> { (&**self).signature() }
#[inline]
fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
#[inline]
fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { unreachable!() }
#[inline]
fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
#[inline]
fn as_u64(&self) -> Option<u64> { (&**self).as_u64() }
#[inline]
fn as_f64(&self) -> Option<f64> { (&**self).as_f64() }
#[inline]
fn as_str(&self) -> Option<&str> { (&**self).as_str() }
#[inline]
fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { (&**self).as_iter() }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() }
}
macro_rules! deref_impl {
($t: ident, $ss: ident, $make_mut: expr) => {
impl<T: RefArg + ?Sized> RefArg for $t<T> {
#[inline]
fn arg_type(&self) -> ArgType { (&**self).arg_type() }
#[inline]
fn signature(&self) -> Signature<'static> { (&**self).signature() }
#[inline]
fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
#[inline]
fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() }
#[inline]
fn as_any_mut<'a>(&'a mut $ss) -> &'a mut any::Any where T: 'static { $make_mut.as_any_mut() }
#[inline]
fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
#[inline]
fn as_u64(&self) -> Option<u64> { (&**self).as_u64() }
#[inline]
fn as_f64(&self) -> Option<f64> { (&**self).as_f64() }
#[inline]
fn as_str(&self) -> Option<&str> { (&**self).as_str() }
#[inline]
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { (&**self).as_iter() }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() }
}
impl<T: DictKey> DictKey for $t<T> {}
impl<T: Arg> Arg for $t<T> {
const ARG_TYPE: ArgType = T::ARG_TYPE;
fn signature() -> Signature<'static> { T::signature() }
}
impl<'a, T: Get<'a>> Get<'a> for $t<T> {
fn get(i: &mut Iter<'a>) -> Option<Self> { T::get(i).map(|v| $t::new(v)) }
}
}
}
impl<T: Append> Append for Box<T> {
fn append(self, i: &mut IterAppend) { let q: T = *self; q.append(i) }
}
deref_impl!(Box, self, &mut **self );
deref_impl!(Rc, self, Rc::get_mut(self).unwrap());
deref_impl!(Arc, self, Arc::get_mut(self).unwrap());
#[cfg(test)]
mod test {
extern crate tempdir;
use {Connection, ConnectionItem, Message, BusType, Path, Signature};
use arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast};
use std::collections::HashMap;
#[test]
fn refarg() {
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/mooh").unwrap();
let m = Message::new_method_call(&c.unique_name(), "/mooh", "com.example.hello", "Hello").unwrap();
let mut vv: Vec<Variant<Box<RefArg>>> = vec!();
vv.push(Variant(Box::new(5i32)));
vv.push(Variant(Box::new(String::from("Hello world"))));
let m = m.append_ref(&vv);
let (f1, f2) = (false, 7u64);
let mut v: Vec<&RefArg> = vec!();
v.push(&f1);
v.push(&f2);
let m = m.append_ref(&v);
let vi32 = vec![7i32, 9i32];
let vstr: Vec<String> = ["This", "is", "dbus", "rs"].iter().map(|&s| s.into()).collect();
let m = m.append_ref(&[&vi32 as &RefArg, &vstr as &RefArg]);
let mut map = HashMap::new();
map.insert(true, String::from("Yes"));
map.insert(false, String::from("No"));
let m = m.append_ref(&[&map as &RefArg, &1.5f64 as &RefArg]);
c.send(m).unwrap();
for n in c.iter(1000) {
if let ConnectionItem::MethodCall(m) = n {
let rv: Vec<Box<RefArg + 'static>> = m.iter_init().collect();
println!("Receiving {:?}", rv);
let rv0: &Variant<Box<RefArg>> = cast(&rv[0]).unwrap();
let rv00: &i32 = cast(&rv0.0).unwrap();
assert_eq!(rv00, &5i32);
assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>());
assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>());
assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>());
let mut diter = rv[6].as_iter().unwrap();
{
let mut mmap: HashMap<bool, String> = HashMap::new();
while let Some(k) = diter.next() {
let x: String = diter.next().unwrap().as_str().unwrap().into();
mmap.insert(*cast::<bool>(&k.box_clone()).unwrap(), x);
}
assert_eq!(mmap[&true], "Yes");
}
let mut iter = rv[6].as_iter().unwrap();
assert!(iter.next().unwrap().as_i64().is_some());
assert!(iter.next().unwrap().as_str().is_some());
assert!(iter.next().unwrap().as_str().is_none());
assert!(iter.next().unwrap().as_i64().is_none());
assert!(iter.next().is_none());
assert!(rv[7].as_f64().unwrap() > 1.0);
assert!(rv[7].as_f64().unwrap() < 2.0);
break;
}
}
}
#[test]
fn message_types() {
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/hello").unwrap();
let m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
let m = m.append1(2000u16);
let m = m.append1(Array::new(&vec![129u8, 5, 254]));
let m = m.append2(Variant(&["Hello", "world"][..]), &[32768u16, 16u16, 12u16][..]);
let m = m.append3(-1i32, &*format!("Hello world"), -3.14f64);
let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64)));
let m = m.append2(Path::new("/a/valid/path").unwrap(), Signature::new("a{sv}").unwrap());
let mut z = HashMap::new();
z.insert(123543u32, true);
z.insert(0u32, false);
let m = m.append1(Dict::new(&z));
let sending = format!("{:?}", m.iter_init());
println!("Sending {}", sending);
c.send(m).unwrap();
for n in c.iter(1000) {
match n {
ConnectionItem::MethodCall(m) => {
use super::Arg;
let receiving = format!("{:?}", m.iter_init());
println!("Receiving {}", receiving);
assert_eq!(sending, receiving);
assert_eq!(2000u16, m.get1().unwrap());
assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..])));
assert_eq!(m.read2::<u16, bool>().unwrap_err(),
TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean });
let mut g = m.iter_init();
let e = g.read::<u32>().unwrap_err();
assert_eq!(e.pos(), 0);
assert_eq!(e.expected_arg_type(), ArgType::UInt32);
assert_eq!(e.found_arg_type(), ArgType::UInt16);
assert!(g.next() && g.next());
let v: Variant<Iter> = g.get().unwrap();
let mut viter = v.0;
assert_eq!(viter.arg_type(), Array::<&str,()>::ARG_TYPE);
let a: Array<&str, _> = viter.get().unwrap();
assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello", "world"]);
assert!(g.next());
assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16
assert!(g.next() && g.next() && g.next() && g.next());
assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64))));
assert!(g.next());
assert_eq!(g.get(), Some(Path::new("/a/valid/path").unwrap()));
assert!(g.next());
assert_eq!(g.get(), Some(Signature::new("a{sv}").unwrap()));
assert!(g.next());
let d: Dict<u32, bool, _> = g.get().unwrap();
let z2: HashMap<_, _> = d.collect();
assert_eq!(z, z2);
break;
}
_ => println!("Got {:?}", n),
}
}
}
}

View File

@ -0,0 +1,242 @@
use super::*;
use {message, Signature};
use std::any;
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
/// A simple wrapper to specify a D-Bus variant.
///
/// See the argument guide and module level documentation for details and examples.
pub struct Variant<T>(pub T);
impl Variant<Box<RefArg>> {
/// Creates a new refarg from an Iter. Mainly for internal use.
pub fn new_refarg<'a>(i: &mut Iter<'a>) -> Option<Self> {
i.recurse(ArgType::Variant).and_then(|mut si| si.get_refarg()).map(|v| Variant(v))
}
}
impl Default for Variant<Box<RefArg>> {
// This is a bit silly, because there is no such thing as a default argument.
// Unfortunately due to a design mistake while making the SignalArgs trait, we'll
// have to work around that by adding a default implementation here.
// https://github.com/diwic/dbus-rs/issues/136
fn default() -> Self { Variant(Box::new(0u8) as Box<RefArg>) }
}
impl<T:Default> Default for Variant<T> {
fn default() -> Self { Variant(T::default()) }
}
impl<T> Arg for Variant<T> {
const ARG_TYPE: ArgType = ArgType::Variant;
fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"v\0") } }
}
impl<T: Arg + Append> Append for Variant<T> {
fn append(self, i: &mut IterAppend) {
let z = self.0;
i.append_container(ArgType::Variant, Some(T::signature().as_cstr()), |s| z.append(s));
}
}
impl Append for Variant<message::MessageItem> {
fn append(self, i: &mut IterAppend) {
let z = self.0;
let asig = z.signature();
let sig = asig.as_cstr();
i.append_container(ArgType::Variant, Some(&sig), |s| z.append(s));
}
}
impl Append for Variant<Box<RefArg>> {
fn append(self, i: &mut IterAppend) {
let z = self.0;
i.append_container(ArgType::Variant, Some(z.signature().as_cstr()), |s| z.append(s));
}
}
impl<'a, T: Get<'a>> Get<'a> for Variant<T> {
fn get(i: &mut Iter<'a>) -> Option<Variant<T>> {
i.recurse(ArgType::Variant).and_then(|mut si| si.get().map(|v| Variant(v)))
}
}
impl<'a> Get<'a> for Variant<Iter<'a>> {
fn get(i: &mut Iter<'a>) -> Option<Variant<Iter<'a>>> {
i.recurse(ArgType::Variant).map(|v| Variant(v))
}
}
/*
impl<'a> Get<'a> for Variant<Box<RefArg>> {
fn get(i: &mut Iter<'a>) -> Option<Variant<Box<RefArg>>> {
i.recurse(ArgType::Variant).and_then(|mut si| si.get_refarg().map(|v| Variant(v)))
}
}
*/
impl<T: RefArg> RefArg for Variant<T> {
fn arg_type(&self) -> ArgType { ArgType::Variant }
fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"v\0") } }
fn append(&self, i: &mut IterAppend) {
let z = &self.0;
i.append_container(ArgType::Variant, Some(z.signature().as_cstr()), |s| z.append(s));
}
#[inline]
fn as_any(&self) -> &any::Any where T: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { self }
#[inline]
fn as_i64(&self) -> Option<i64> { self.0.as_i64() }
#[inline]
fn as_u64(&self) -> Option<u64> { self.0.as_u64() }
#[inline]
fn as_f64(&self) -> Option<f64> { self.0.as_f64() }
#[inline]
fn as_str(&self) -> Option<&str> { self.0.as_str() }
#[inline]
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> {
use std::iter;
let z: &RefArg = &self.0;
Some(Box::new(iter::once(z)))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(Variant(self.0.box_clone())) }
}
macro_rules! struct_impl {
( $($n: ident $t: ident,)+ ) => {
/// Tuples are represented as D-Bus structs.
impl<$($t: Arg),*> Arg for ($($t,)*) {
const ARG_TYPE: ArgType = ArgType::Struct;
fn signature() -> Signature<'static> {
let mut s = String::from("(");
$( s.push_str(&$t::signature()); )*
s.push_str(")");
Signature::from(s)
}
}
impl<$($t: Append),*> Append for ($($t,)*) {
fn append(self, i: &mut IterAppend) {
let ( $($n,)*) = self;
i.append_container(ArgType::Struct, None, |s| { $( $n.append(s); )* });
}
}
impl<'a, $($t: Get<'a>),*> Get<'a> for ($($t,)*) {
fn get(i: &mut Iter<'a>) -> Option<Self> {
let si = i.recurse(ArgType::Struct);
if si.is_none() { return None; }
let mut si = si.unwrap();
let mut _valid_item = true;
$(
if !_valid_item { return None; }
let $n: Option<$t> = si.get();
if $n.is_none() { return None; }
_valid_item = si.next();
)*
Some(($( $n.unwrap(), )* ))
}
}
impl<$($t: RefArg),*> RefArg for ($($t,)*) {
fn arg_type(&self) -> ArgType { ArgType::Struct }
fn signature(&self) -> Signature<'static> {
let &( $(ref $n,)*) = self;
let mut s = String::from("(");
$( s.push_str(&$n.signature()); )*
s.push_str(")");
Signature::from(s)
}
fn append(&self, i: &mut IterAppend) {
let &( $(ref $n,)*) = self;
i.append_container(ArgType::Struct, None, |s| { $( $n.append(s); )* });
}
fn as_any(&self) -> &any::Any where Self: 'static { self }
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> {
let &( $(ref $n,)*) = self;
let v = vec!(
$( $n as &RefArg, )*
);
Some(Box::new(v.into_iter()))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
let &( $(ref $n,)*) = self;
let mut z = vec!();
$( z.push($n.box_clone()); )*
Box::new(z)
}
}
}} // macro_rules end
struct_impl!(a A,);
struct_impl!(a A, b B,);
struct_impl!(a A, b B, c C,);
struct_impl!(a A, b B, c C, d D,);
struct_impl!(a A, b B, c C, d D, e E,);
struct_impl!(a A, b B, c C, d D, e E, f F,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J, k K,);
struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J, k K, l L,);
impl RefArg for Vec<Box<RefArg>> {
fn arg_type(&self) -> ArgType { ArgType::Struct }
fn signature(&self) -> Signature<'static> {
let mut s = String::from("(");
for z in self {
s.push_str(&z.signature());
}
s.push_str(")");
Signature::from(s)
}
fn append(&self, i: &mut IterAppend) {
i.append_container(ArgType::Struct, None, |s| {
for z in self { z.append(s); }
});
}
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> {
Some(Box::new(self.iter().map(|b| &**b)))
}
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> {
let t: Vec<Box<RefArg + 'static>> = self.iter().map(|x| x.box_clone()).collect();
Box::new(t)
}
}
impl Append for message::MessageItem {
fn append(self, i: &mut IterAppend) {
message::append_messageitem(&mut i.0, &self)
}
}
impl<'a> Get<'a> for message::MessageItem {
fn get(i: &mut Iter<'a>) -> Option<Self> {
message::get_messageitem(&mut i.0)
}
}
impl RefArg for message::MessageItem {
fn arg_type(&self) -> ArgType { ArgType::from_i32(self.array_type()).unwrap() }
fn signature(&self) -> Signature<'static> { message::MessageItem::signature(&self) }
fn append(&self, i: &mut IterAppend) { message::append_messageitem(&mut i.0, self) }
#[inline]
fn as_any(&self) -> &any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self }
#[inline]
fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) }
}

733
third_party/rust/dbus/src/connection.rs vendored Normal file
View File

@ -0,0 +1,733 @@
use super::{Error, ffi, to_c_str, c_str_to_slice, Watch, Message, MessageType, BusName, Path, ConnPath};
use super::{RequestNameReply, ReleaseNameReply, BusType};
use super::watch::WatchList;
use std::{fmt, mem, ptr, thread, panic, ops};
use std::collections::VecDeque;
use std::cell::{Cell, RefCell};
use std::os::unix::io::RawFd;
use std::os::raw::{c_void, c_char, c_int, c_uint};
/// The type of function to use for replacing the message callback.
///
/// See the documentation for Connection::replace_message_callback for more information.
pub type MessageCallback = Box<FnMut(&Connection, Message) -> bool + 'static>;
#[repr(C)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
/// Flags to use for Connection::register_name.
///
/// More than one flag can be specified, if so just add their values.
pub enum DBusNameFlag {
/// Allow another service to become the primary owner if requested
AllowReplacement = ffi::DBUS_NAME_FLAG_ALLOW_REPLACEMENT as isize,
/// Request to replace the current primary owner
ReplaceExisting = ffi::DBUS_NAME_FLAG_REPLACE_EXISTING as isize,
/// If we can not become the primary owner do not place us in the queue
DoNotQueue = ffi::DBUS_NAME_FLAG_DO_NOT_QUEUE as isize,
}
impl DBusNameFlag {
/// u32 value of flag.
pub fn value(self) -> u32 { self as u32 }
}
/// When listening for incoming events on the D-Bus, this enum will tell you what type
/// of incoming event has happened.
#[derive(Debug)]
pub enum ConnectionItem {
/// No event between now and timeout
Nothing,
/// Incoming method call
MethodCall(Message),
/// Incoming signal
Signal(Message),
/// Incoming method return, including method return errors (mostly used for Async I/O)
MethodReturn(Message),
}
impl From<Message> for ConnectionItem {
fn from(m: Message) -> Self {
let mtype = m.msg_type();
match mtype {
MessageType::Signal => ConnectionItem::Signal(m),
MessageType::MethodReturn => ConnectionItem::MethodReturn(m),
MessageType::Error => ConnectionItem::MethodReturn(m),
MessageType::MethodCall => ConnectionItem::MethodCall(m),
_ => panic!("unknown message type {:?} received from D-Bus", mtype),
}
}
}
/// ConnectionItem iterator
pub struct ConnectionItems<'a> {
c: &'a Connection,
timeout_ms: Option<i32>,
end_on_timeout: bool,
handlers: MsgHandlerList,
}
impl<'a> ConnectionItems<'a> {
/// Builder method that adds a new msg handler.
///
/// Note: Likely to changed/refactored/removed in next release
pub fn with<H: 'static + MsgHandler>(mut self, h: H) -> Self {
self.handlers.push(Box::new(h)); self
}
// Returns true if processed, false if not
fn process_handlers(&mut self, ci: &ConnectionItem) -> bool {
let m = match *ci {
ConnectionItem::MethodReturn(ref msg) => msg,
ConnectionItem::Signal(ref msg) => msg,
ConnectionItem::MethodCall(ref msg) => msg,
ConnectionItem::Nothing => return false,
};
msghandler_process(&mut self.handlers, m, &self.c)
}
/// Access and modify message handlers
///
/// Note: Likely to changed/refactored/removed in next release
pub fn msg_handlers(&mut self) -> &mut Vec<Box<MsgHandler>> { &mut self.handlers }
/// Creates a new ConnectionItems iterator
///
/// For io_timeout, setting None means the fds will not be read/written. I e, only pending
/// items in libdbus's internal queue will be processed.
///
/// For end_on_timeout, setting false will means that the iterator will never finish (unless
/// the D-Bus server goes down). Instead, ConnectionItem::Nothing will be returned in case no
/// items are in queue.
pub fn new(conn: &'a Connection, io_timeout: Option<i32>, end_on_timeout: bool) -> Self {
ConnectionItems {
c: conn,
timeout_ms: io_timeout,
end_on_timeout: end_on_timeout,
handlers: Vec::new(),
}
}
}
impl<'a> Iterator for ConnectionItems<'a> {
type Item = ConnectionItem;
fn next(&mut self) -> Option<ConnectionItem> {
loop {
if self.c.i.filter_cb.borrow().is_none() { panic!("ConnectionItems::next called recursively or with a MessageCallback set to None"); }
let i: Option<ConnectionItem> = self.c.next_msg().map(|x| x.into());
if let Some(ci) = i {
if !self.process_handlers(&ci) { return Some(ci); }
}
if let Some(t) = self.timeout_ms {
let r = unsafe { ffi::dbus_connection_read_write_dispatch(self.c.conn(), t as c_int) };
self.c.check_panic();
if !self.c.i.pending_items.borrow().is_empty() { continue };
if r == 0 { return None; }
}
let r = unsafe { ffi::dbus_connection_dispatch(self.c.conn()) };
self.c.check_panic();
if !self.c.i.pending_items.borrow().is_empty() { continue };
if r == ffi::DBusDispatchStatus::DataRemains { continue };
if r == ffi::DBusDispatchStatus::Complete { return if self.end_on_timeout { None } else { Some(ConnectionItem::Nothing) } };
panic!("dbus_connection_dispatch failed");
}
}
}
/// Iterator over incoming messages on a connection.
#[derive(Debug, Clone)]
pub struct ConnMsgs<C> {
/// The connection or some reference to it.
pub conn: C,
/// How many ms dbus should block, waiting for incoming messages until timing out.
///
/// If set to None, the dbus library will not read/write from file descriptors at all.
/// Instead the iterator will end when there's nothing currently in the queue.
pub timeout_ms: Option<u32>,
}
impl<C: ops::Deref<Target = Connection>> Iterator for ConnMsgs<C> {
type Item = Message;
fn next(&mut self) -> Option<Self::Item> {
loop {
let iconn = &self.conn.i;
if iconn.filter_cb.borrow().is_none() { panic!("ConnMsgs::next called recursively or with a MessageCallback set to None"); }
let i = self.conn.next_msg();
if let Some(ci) = i { return Some(ci); }
if let Some(t) = self.timeout_ms {
let r = unsafe { ffi::dbus_connection_read_write_dispatch(self.conn.conn(), t as c_int) };
self.conn.check_panic();
if !iconn.pending_items.borrow().is_empty() { continue };
if r == 0 { return None; }
}
let r = unsafe { ffi::dbus_connection_dispatch(self.conn.conn()) };
self.conn.check_panic();
if !iconn.pending_items.borrow().is_empty() { continue };
if r == ffi::DBusDispatchStatus::DataRemains { continue };
if r == ffi::DBusDispatchStatus::Complete { return None }
panic!("dbus_connection_dispatch failed");
}
}
}
/* Since we register callbacks with userdata pointers,
we need to make sure the connection pointer does not move around.
Hence this extra indirection. */
struct IConnection {
conn: Cell<*mut ffi::DBusConnection>,
pending_items: RefCell<VecDeque<Message>>,
watches: Option<Box<WatchList>>,
handlers: RefCell<MsgHandlerList>,
filter_cb: RefCell<Option<MessageCallback>>,
filter_cb_panic: RefCell<thread::Result<()>>,
}
/// A D-Bus connection. Start here if you want to get on the D-Bus!
pub struct Connection {
i: Box<IConnection>,
}
pub fn conn_handle(c: &Connection) -> *mut ffi::DBusConnection {
c.i.conn.get()
}
extern "C" fn filter_message_cb(conn: *mut ffi::DBusConnection, msg: *mut ffi::DBusMessage,
user_data: *mut c_void) -> ffi::DBusHandlerResult {
let i: &IConnection = unsafe { mem::transmute(user_data) };
let connref: panic::AssertUnwindSafe<&Connection> = unsafe { mem::transmute(&i) };
if i.conn.get() != conn || i.filter_cb_panic.try_borrow().is_err() {
// This should never happen, but let's be extra sure
// process::abort(); ??
return ffi::DBusHandlerResult::Handled;
}
if i.filter_cb_panic.borrow().is_err() {
// We're in panic mode. Let's quit this ASAP
return ffi::DBusHandlerResult::Handled;
}
let fcb = panic::AssertUnwindSafe(&i.filter_cb);
let r = panic::catch_unwind(|| {
let m = super::message::message_from_ptr(msg, true);
let mut cb = fcb.borrow_mut().take().unwrap(); // Take the callback out while we call it.
let r = cb(connref.0, m);
let mut cb2 = fcb.borrow_mut(); // If the filter callback has not been replaced, put it back in.
if cb2.is_none() { *cb2 = Some(cb) };
r
});
match r {
Ok(false) => ffi::DBusHandlerResult::NotYetHandled,
Ok(true) => ffi::DBusHandlerResult::Handled,
Err(e) => {
*i.filter_cb_panic.borrow_mut() = Err(e);
ffi::DBusHandlerResult::Handled
}
}
}
fn default_filter_callback(c: &Connection, m: Message) -> bool {
let b = m.msg_type() == MessageType::Signal;
c.i.pending_items.borrow_mut().push_back(m);
b
}
extern "C" fn object_path_message_cb(_conn: *mut ffi::DBusConnection, _msg: *mut ffi::DBusMessage,
_user_data: *mut c_void) -> ffi::DBusHandlerResult {
/* Already pushed in filter_message_cb, so we just set the handled flag here to disable the
"default" handler. */
ffi::DBusHandlerResult::Handled
}
impl Connection {
#[inline(always)]
fn conn(&self) -> *mut ffi::DBusConnection {
self.i.conn.get()
}
fn conn_from_ptr(conn: *mut ffi::DBusConnection) -> Result<Connection, Error> {
let mut c = Connection { i: Box::new(IConnection {
conn: Cell::new(conn),
pending_items: RefCell::new(VecDeque::new()),
watches: None,
handlers: RefCell::new(vec!()),
filter_cb: RefCell::new(Some(Box::new(default_filter_callback))),
filter_cb_panic: RefCell::new(Ok(())),
})};
/* No, we don't want our app to suddenly quit if dbus goes down */
unsafe { ffi::dbus_connection_set_exit_on_disconnect(conn, 0) };
assert!(unsafe {
ffi::dbus_connection_add_filter(c.conn(), Some(filter_message_cb), mem::transmute(&*c.i), None)
} != 0);
c.i.watches = Some(WatchList::new(&c, Box::new(|_| {})));
Ok(c)
}
/// Creates a new D-Bus connection.
pub fn get_private(bus: BusType) -> Result<Connection, Error> {
let mut e = Error::empty();
let conn = unsafe { ffi::dbus_bus_get_private(bus, e.get_mut()) };
if conn == ptr::null_mut() {
return Err(e)
}
Self::conn_from_ptr(conn)
}
/// Creates a new D-Bus connection to a remote address.
///
/// Note: for all common cases (System / Session bus) you probably want "get_private" instead.
pub fn open_private(address: &str) -> Result<Connection, Error> {
let mut e = Error::empty();
let conn = unsafe { ffi::dbus_connection_open_private(to_c_str(address).as_ptr(), e.get_mut()) };
if conn == ptr::null_mut() {
return Err(e)
}
Self::conn_from_ptr(conn)
}
/// Registers a new D-Bus connection with the bus.
///
/// Note: `get_private` does this automatically, useful with `open_private`
pub fn register(&self) -> Result<(), Error> {
let mut e = Error::empty();
if !unsafe { ffi::dbus_bus_register(self.conn(), e.get_mut()) } {
Err(e)
} else {
Ok(())
}
}
/// Gets whether the connection is currently open.
pub fn is_connected(&self) -> bool {
unsafe { ffi::dbus_connection_get_is_connected(self.conn()) }
}
/// Sends a message over the D-Bus and waits for a reply.
/// This is usually used for method calls.
pub fn send_with_reply_and_block(&self, msg: Message, timeout_ms: i32) -> Result<Message, Error> {
let mut e = Error::empty();
let response = unsafe {
ffi::dbus_connection_send_with_reply_and_block(self.conn(), super::message::get_message_ptr(&msg),
timeout_ms as c_int, e.get_mut())
};
if response == ptr::null_mut() {
return Err(e);
}
Ok(super::message::message_from_ptr(response, false))
}
/// Sends a message over the D-Bus without waiting. Useful for sending signals and method call replies.
pub fn send(&self, msg: Message) -> Result<u32,()> {
let mut serial = 0u32;
let r = unsafe { ffi::dbus_connection_send(self.conn(), super::message::get_message_ptr(&msg), &mut serial) };
if r == 0 { return Err(()); }
unsafe { ffi::dbus_connection_flush(self.conn()) };
Ok(serial)
}
/// Sends a message over the D-Bus, returning a MessageReply.
///
/// Call add_handler on the result to start waiting for reply. This should be done before next call to `incoming` or `iter`.
pub fn send_with_reply<'a, F: FnOnce(Result<&Message, Error>) + 'a>(&self, msg: Message, f: F) -> Result<MessageReply<F>, ()> {
let serial = self.send(msg)?;
Ok(MessageReply(Some(f), serial))
}
/// Adds a message handler to the connection.
///
/// # Example
///
/// ```
/// use std::{cell, rc};
/// use dbus::{Connection, Message, BusType};
///
/// let c = Connection::get_private(BusType::Session).unwrap();
/// let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
///
/// let done: rc::Rc<cell::Cell<bool>> = Default::default();
/// let done2 = done.clone();
/// c.add_handler(c.send_with_reply(m, move |reply| {
/// let v: Vec<&str> = reply.unwrap().read1().unwrap();
/// println!("The names on the D-Bus are: {:?}", v);
/// done2.set(true);
/// }).unwrap());
/// while !done.get() { c.incoming(100).next(); }
/// ```
pub fn add_handler<H: MsgHandler + 'static>(&self, h: H) {
let h = Box::new(h);
self.i.handlers.borrow_mut().push(h);
}
/// Removes a MsgHandler from the connection.
///
/// If there are many MsgHandlers, it is not specified which one will be returned.
///
/// There might be more methods added later on, which give better ways to deal
/// with the list of MsgHandler currently on the connection. If this would help you,
/// please [file an issue](https://github.com/diwic/dbus-rs/issues).
pub fn extract_handler(&self) -> Option<Box<MsgHandler>> {
self.i.handlers.borrow_mut().pop()
}
/// Get the connection's unique name.
pub fn unique_name(&self) -> String {
let c = unsafe { ffi::dbus_bus_get_unique_name(self.conn()) };
c_str_to_slice(&c).unwrap_or("").to_string()
}
/// Check if there are new incoming events
///
/// If there are no incoming events, ConnectionItems::Nothing will be returned.
/// See ConnectionItems::new if you want to customize this behaviour.
pub fn iter(&self, timeout_ms: i32) -> ConnectionItems {
ConnectionItems::new(self, Some(timeout_ms), false)
}
/// Check if there are new incoming events
///
/// Supersedes "iter".
pub fn incoming(&self, timeout_ms: u32) -> ConnMsgs<&Self> {
ConnMsgs { conn: &self, timeout_ms: Some(timeout_ms) }
}
/// Register an object path.
pub fn register_object_path(&self, path: &str) -> Result<(), Error> {
let mut e = Error::empty();
let p = to_c_str(path);
let vtable = ffi::DBusObjectPathVTable {
unregister_function: None,
message_function: Some(object_path_message_cb),
dbus_internal_pad1: None,
dbus_internal_pad2: None,
dbus_internal_pad3: None,
dbus_internal_pad4: None,
};
let r = unsafe {
let user_data: *mut c_void = mem::transmute(&*self.i);
ffi::dbus_connection_try_register_object_path(self.conn(), p.as_ptr(), &vtable, user_data, e.get_mut())
};
if r == 0 { Err(e) } else { Ok(()) }
}
/// Unregister an object path.
pub fn unregister_object_path(&self, path: &str) {
let p = to_c_str(path);
let r = unsafe { ffi::dbus_connection_unregister_object_path(self.conn(), p.as_ptr()) };
if r == 0 { panic!("Out of memory"); }
}
/// List registered object paths.
pub fn list_registered_object_paths(&self, path: &str) -> Vec<String> {
let p = to_c_str(path);
let mut clist: *mut *mut c_char = ptr::null_mut();
let r = unsafe { ffi::dbus_connection_list_registered(self.conn(), p.as_ptr(), &mut clist) };
if r == 0 { panic!("Out of memory"); }
let mut v = Vec::new();
let mut i = 0;
loop {
let s = unsafe {
let citer = clist.offset(i);
if *citer == ptr::null_mut() { break };
mem::transmute(citer)
};
v.push(format!("{}", c_str_to_slice(s).unwrap()));
i += 1;
}
unsafe { ffi::dbus_free_string_array(clist) };
v
}
/// Register a name.
pub fn register_name(&self, name: &str, flags: u32) -> Result<RequestNameReply, Error> {
let mut e = Error::empty();
let n = to_c_str(name);
let r = unsafe { ffi::dbus_bus_request_name(self.conn(), n.as_ptr(), flags, e.get_mut()) };
if r == -1 { Err(e) } else { Ok(unsafe { mem::transmute(r) }) }
}
/// Release a name.
pub fn release_name(&self, name: &str) -> Result<ReleaseNameReply, Error> {
let mut e = Error::empty();
let n = to_c_str(name);
let r = unsafe { ffi::dbus_bus_release_name(self.conn(), n.as_ptr(), e.get_mut()) };
if r == -1 { Err(e) } else { Ok(unsafe { mem::transmute(r) }) }
}
/// Add a match rule to match messages on the message bus.
///
/// See the `unity_focused_window` example for how to use this to catch signals.
/// (The syntax of the "rule" string is specified in the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules).)
pub fn add_match(&self, rule: &str) -> Result<(), Error> {
let mut e = Error::empty();
let n = to_c_str(rule);
unsafe { ffi::dbus_bus_add_match(self.conn(), n.as_ptr(), e.get_mut()) };
if e.name().is_some() { Err(e) } else { Ok(()) }
}
/// Remove a match rule to match messages on the message bus.
pub fn remove_match(&self, rule: &str) -> Result<(), Error> {
let mut e = Error::empty();
let n = to_c_str(rule);
unsafe { ffi::dbus_bus_remove_match(self.conn(), n.as_ptr(), e.get_mut()) };
if e.name().is_some() { Err(e) } else { Ok(()) }
}
/// Async I/O: Get an up-to-date list of file descriptors to watch.
///
/// See the `Watch` struct for an example.
pub fn watch_fds(&self) -> Vec<Watch> {
self.i.watches.as_ref().unwrap().get_enabled_fds()
}
/// Async I/O: Call this function whenever you detected an event on the Fd,
/// Flags are a set of WatchEvent bits.
/// The returned iterator will return pending items only, never block for new events.
///
/// See the `Watch` struct for an example.
pub fn watch_handle(&self, fd: RawFd, flags: c_uint) -> ConnectionItems {
self.i.watches.as_ref().unwrap().watch_handle(fd, flags);
ConnectionItems::new(self, None, true)
}
/// Create a convenience struct for easier calling of many methods on the same destination and path.
pub fn with_path<'a, D: Into<BusName<'a>>, P: Into<Path<'a>>>(&'a self, dest: D, path: P, timeout_ms: i32) ->
ConnPath<'a, &'a Connection> {
ConnPath { conn: self, dest: dest.into(), path: path.into(), timeout: timeout_ms }
}
/// Replace the default message callback. Returns the previously set callback.
///
/// By default, when you call ConnectionItems::next, all relevant incoming messages
/// are returned through the ConnectionItems iterator, and
/// irrelevant messages are passed on to libdbus's default handler.
/// If you need to customize this behaviour (i e, to handle all incoming messages yourself),
/// you can set this message callback yourself. A few caveats apply:
///
/// Return true from the callback to disable libdbus's internal handling of the message, or
/// false to allow it. In other words, true and false correspond to
/// `DBUS_HANDLER_RESULT_HANDLED` and `DBUS_HANDLER_RESULT_NOT_YET_HANDLED` respectively.
///
/// Be sure to call the previously set callback from inside your callback,
/// if you want, e.g. ConnectionItems::next to yield the message.
///
/// You can unset the message callback (might be useful to satisfy the borrow checker), but
/// you will get a panic if you call ConnectionItems::next while the message callback is unset.
/// The message callback will be temporary unset while inside a message callback, so calling
/// ConnectionItems::next recursively will also result in a panic.
///
/// If your message callback panics, ConnectionItems::next will panic, too.
///
/// # Examples
///
/// Replace the default callback with our own:
///
/// ```ignore
/// use dbus::{Connection, BusType};
/// let c = Connection::get_private(BusType::Session).unwrap();
/// // Set our callback
/// c.replace_message_callback(Some(Box::new(move |conn, msg| {
/// println!("Got message: {:?}", msg.get_items());
/// // Let libdbus handle some things by default,
/// // like "nonexistent object" error replies to method calls
/// false
/// })));
///
/// for _ in c.iter(1000) {
/// // Only `ConnectionItem::Nothing` would be ever yielded here.
/// }
/// ```
///
/// Chain our callback to filter out some messages before `iter().next()`:
///
/// ```
/// use dbus::{Connection, BusType, MessageType};
/// let c = Connection::get_private(BusType::Session).unwrap();
/// // Take the previously set callback
/// let mut old_cb = c.replace_message_callback(None).unwrap();
/// // Set our callback
/// c.replace_message_callback(Some(Box::new(move |conn, msg| {
/// // Handle all signals on the spot
/// if msg.msg_type() == MessageType::Signal {
/// println!("Got signal: {:?}", msg.get_items());
/// // Stop all further processing of the message
/// return true;
/// }
/// // Delegate the rest of the messages to the previous callback
/// // in chain, e.g. to have them yielded by `iter().next()`
/// old_cb(conn, msg)
/// })));
///
/// # if false {
/// for _ in c.iter(1000) {
/// // `ConnectionItem::Signal` would never be yielded here.
/// }
/// # }
/// ```
pub fn replace_message_callback(&self, f: Option<MessageCallback>) -> Option<MessageCallback> {
mem::replace(&mut *self.i.filter_cb.borrow_mut(), f)
}
/// Sets a callback to be called if a file descriptor status changes.
///
/// For async I/O. In rare cases, the number of fds to poll for read/write can change.
/// If this ever happens, you'll get a callback. The watch changed is provided as a parameter.
///
/// In rare cases this might not even happen in the thread calling anything on the connection,
/// so the callback needs to be `Send`.
/// A mutex is held during the callback. If you try to call set_watch_callback from a callback,
/// you will deadlock.
///
/// (Previously, this was instead put in a ConnectionItem queue, but this was not working correctly.
/// see https://github.com/diwic/dbus-rs/issues/99 for additional info.)
pub fn set_watch_callback(&self, f: Box<Fn(Watch) + Send>) { self.i.watches.as_ref().unwrap().set_on_update(f); }
fn check_panic(&self) {
let p = mem::replace(&mut *self.i.filter_cb_panic.borrow_mut(), Ok(()));
if let Err(perr) = p { panic::resume_unwind(perr); }
}
fn next_msg(&self) -> Option<Message> {
while let Some(msg) = self.i.pending_items.borrow_mut().pop_front() {
let mut v: MsgHandlerList = mem::replace(&mut *self.i.handlers.borrow_mut(), vec!());
let b = msghandler_process(&mut v, &msg, self);
let mut v2 = self.i.handlers.borrow_mut();
v.append(&mut *v2);
*v2 = v;
if !b { return Some(msg) };
};
None
}
}
impl Drop for Connection {
fn drop(&mut self) {
unsafe {
ffi::dbus_connection_close(self.conn());
ffi::dbus_connection_unref(self.conn());
}
}
}
impl fmt::Debug for Connection {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "D-Bus Connection({})", self.unique_name())
}
}
#[derive(Clone, Debug)]
/// Type of messages to be handled by a MsgHandler.
///
/// Note: More variants can be added in the future; but unless you're writing your own D-Bus engine
/// you should not have to match on these anyway.
pub enum MsgHandlerType {
/// Handle all messages
All,
/// Handle only messages of a specific type
MsgType(MessageType),
/// Handle only method replies with this serial number
Reply(u32),
}
impl MsgHandlerType {
fn matches_msg(&self, m: &Message) -> bool {
match *self {
MsgHandlerType::All => true,
MsgHandlerType::MsgType(t) => m.msg_type() == t,
MsgHandlerType::Reply(serial) => {
let t = m.msg_type();
((t == MessageType::MethodReturn) || (t == MessageType::Error)) && (m.get_reply_serial() == Some(serial))
}
}
}
}
/// A trait for handling incoming messages.
pub trait MsgHandler {
/// Type of messages for which the handler will be called
///
/// Note: The return value of this function might be cached, so it must return the same value all the time.
fn handler_type(&self) -> MsgHandlerType;
/// Function to be called if the message matches the MsgHandlerType
fn handle_msg(&mut self, _msg: &Message) -> Option<MsgHandlerResult> { None }
}
/// The result from MsgHandler::handle.
#[derive(Debug, Default)]
pub struct MsgHandlerResult {
/// Indicates that the message has been dealt with and should not be processed further.
pub handled: bool,
/// Indicates that this MsgHandler no longer wants to receive messages and should be removed.
pub done: bool,
/// Messages to send (e g, a reply to a method call)
pub reply: Vec<Message>,
}
type MsgHandlerList = Vec<Box<MsgHandler>>;
fn msghandler_process(v: &mut MsgHandlerList, m: &Message, c: &Connection) -> bool {
let mut ii: isize = -1;
loop {
ii += 1;
let i = ii as usize;
if i >= v.len() { return false };
if !v[i].handler_type().matches_msg(m) { continue; }
if let Some(r) = v[i].handle_msg(m) {
for msg in r.reply.into_iter() { c.send(msg).unwrap(); }
if r.done { v.remove(i); ii -= 1; }
if r.handled { return true; }
}
}
}
/// The struct returned from `Connection::send_and_reply`.
///
/// It implements the `MsgHandler` trait so you can use `Connection::add_handler`.
pub struct MessageReply<F>(Option<F>, u32);
impl<'a, F: FnOnce(Result<&Message, Error>) + 'a> MsgHandler for MessageReply<F> {
fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::Reply(self.1) }
fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
let e = match msg.msg_type() {
MessageType::MethodReturn => Ok(msg),
MessageType::Error => Err(msg.set_error_from_msg().unwrap_err()),
_ => unreachable!(),
};
debug_assert_eq!(msg.get_reply_serial(), Some(self.1));
self.0.take().unwrap()(e);
return Some(MsgHandlerResult { handled: true, done: true, reply: Vec::new() })
}
}
#[test]
fn message_reply() {
use std::{cell, rc};
let c = Connection::get_private(BusType::Session).unwrap();
assert!(c.is_connected());
let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
let quit = rc::Rc::new(cell::Cell::new(false));
let quit2 = quit.clone();
let reply = c.send_with_reply(m, move |result| {
let r = result.unwrap();
let _: ::arg::Array<&str, _> = r.get1().unwrap();
quit2.set(true);
}).unwrap();
for _ in c.iter(1000).with(reply) { if quit.get() { return; } }
assert!(false);
}

281
third_party/rust/dbus/src/lib.rs vendored Normal file
View File

@ -0,0 +1,281 @@
//! D-Bus bindings for Rust
//!
//! [D-Bus](http://dbus.freedesktop.org/) is a message bus, and is mainly used in Linux
//! for communication between processes. It is present by default on almost every
//! Linux distribution out there, and runs in two instances - one per session, and one
//! system-wide.
//!
//! In addition to the API documentation, which you're currently reading, you might want to
//! look in the examples directory, which contains many examples and an argument guide.
//! README.md also contain a few quick "getting started" examples.
//!
//! In addition to this crate, there are two companion crates, dbus-codegen for generating Rust
//! code from D-Bus introspection data, and dbus-tokio for integrating D-Bus with [Tokio](http://tokio.rs).
//! However, at the time of this writing, these are far less mature than this crate.
#![warn(missing_docs)]
extern crate libc;
pub use ffi::DBusBusType as BusType;
pub use connection::DBusNameFlag as NameFlag;
pub use ffi::DBusRequestNameReply as RequestNameReply;
pub use ffi::DBusReleaseNameReply as ReleaseNameReply;
pub use ffi::DBusMessageType as MessageType;
pub use message::{Message, MessageItem, MessageItemArray, FromMessageItem, OwnedFd, ArrayError, ConnPath};
pub use connection::{Connection, ConnectionItems, ConnectionItem, ConnMsgs, MsgHandler, MsgHandlerResult, MsgHandlerType, MessageCallback};
pub use prop::PropHandler;
pub use prop::Props;
pub use watch::{Watch, WatchEvent};
pub use signalargs::SignalArgs;
/// A TypeSig describes the type of a MessageItem.
#[deprecated(note="Use Signature instead")]
pub type TypeSig<'a> = std::borrow::Cow<'a, str>;
use std::ffi::{CString, CStr};
use std::ptr;
use std::os::raw::c_char;
#[allow(missing_docs)]
extern crate libdbus_sys as ffi;
mod message;
mod prop;
mod watch;
mod connection;
mod signalargs;
mod strings;
pub use strings::{Signature, Path, Interface, Member, ErrorName, BusName};
pub mod arg;
pub mod stdintf;
pub mod tree;
static INITDBUS: std::sync::Once = std::sync::ONCE_INIT;
fn init_dbus() {
INITDBUS.call_once(|| {
if unsafe { ffi::dbus_threads_init_default() } == 0 {
panic!("Out of memory when trying to initialize D-Bus library!");
}
});
}
/// D-Bus Error wrapper.
pub struct Error {
e: ffi::DBusError,
}
unsafe impl Send for Error {}
// Note! For this Sync impl to be safe, it requires that no functions that take &self,
// actually calls into FFI. All functions that call into FFI with a ffi::DBusError
// must take &mut self.
unsafe impl Sync for Error {}
fn c_str_to_slice(c: & *const c_char) -> Option<&str> {
if *c == ptr::null() { None }
else { std::str::from_utf8( unsafe { CStr::from_ptr(*c).to_bytes() }).ok() }
}
fn to_c_str(n: &str) -> CString { CString::new(n.as_bytes()).unwrap() }
impl Error {
/// Create a new custom D-Bus Error.
pub fn new_custom(name: &str, message: &str) -> Error {
let n = to_c_str(name);
let m = to_c_str(&message.replace("%","%%"));
let mut e = Error::empty();
unsafe { ffi::dbus_set_error(e.get_mut(), n.as_ptr(), m.as_ptr()) };
e
}
fn empty() -> Error {
init_dbus();
let mut e = ffi::DBusError {
name: ptr::null(),
message: ptr::null(),
dummy: 0,
padding1: ptr::null()
};
unsafe { ffi::dbus_error_init(&mut e); }
Error{ e: e }
}
/// Error name/type, e g 'org.freedesktop.DBus.Error.Failed'
pub fn name(&self) -> Option<&str> {
c_str_to_slice(&self.e.name)
}
/// Custom message, e g 'Could not find a matching object path'
pub fn message(&self) -> Option<&str> {
c_str_to_slice(&self.e.message)
}
fn get_mut(&mut self) -> &mut ffi::DBusError { &mut self.e }
}
impl Drop for Error {
fn drop(&mut self) {
unsafe { ffi::dbus_error_free(&mut self.e); }
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "D-Bus error: {} ({})", self.message().unwrap_or(""),
self.name().unwrap_or(""))
}
}
impl std::error::Error for Error {
fn description(&self) -> &str { "D-Bus error" }
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(),std::fmt::Error> {
if let Some(x) = self.message() {
write!(f, "{:?}", x.to_string())
} else { Ok(()) }
}
}
impl From<arg::TypeMismatchError> for Error {
fn from(t: arg::TypeMismatchError) -> Error {
Error::new_custom("org.freedesktop.DBus.Error.Failed", &format!("{}", t))
}
}
impl From<tree::MethodErr> for Error {
fn from(t: tree::MethodErr) -> Error {
Error::new_custom(t.errorname(), t.description())
}
}
#[cfg(test)]
mod test {
use super::{Connection, Message, BusType, MessageItem, ConnectionItem, NameFlag,
RequestNameReply, ReleaseNameReply};
#[test]
fn connection() {
let c = Connection::get_private(BusType::Session).unwrap();
let n = c.unique_name();
assert!(n.starts_with(":1."));
println!("Connected to DBus, unique name: {}", n);
}
#[test]
fn invalid_message() {
let c = Connection::get_private(BusType::Session).unwrap();
let m = Message::new_method_call("foo.bar", "/", "foo.bar", "FooBar").unwrap();
let e = c.send_with_reply_and_block(m, 2000).err().unwrap();
assert!(e.name().unwrap() == "org.freedesktop.DBus.Error.ServiceUnknown");
}
#[test]
fn message_listnames() {
let c = Connection::get_private(BusType::Session).unwrap();
let m = Message::method_call(&"org.freedesktop.DBus".into(), &"/".into(),
&"org.freedesktop.DBus".into(), &"ListNames".into());
let r = c.send_with_reply_and_block(m, 2000).unwrap();
let reply = r.get_items();
println!("{:?}", reply);
}
#[test]
fn message_namehasowner() {
let c = Connection::get_private(BusType::Session).unwrap();
let mut m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "NameHasOwner").unwrap();
m.append_items(&[MessageItem::Str("org.freedesktop.DBus".to_string())]);
let r = c.send_with_reply_and_block(m, 2000).unwrap();
let reply = r.get_items();
println!("{:?}", reply);
assert_eq!(reply, vec!(MessageItem::Bool(true)));
}
#[test]
fn object_path() {
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
let thread = ::std::thread::spawn(move || {
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/hello").unwrap();
// println!("Waiting...");
tx.send(c.unique_name()).unwrap();
for n in c.iter(1000) {
// println!("Found message... ({})", n);
match n {
ConnectionItem::MethodCall(ref m) => {
let reply = Message::new_method_return(m).unwrap();
c.send(reply).unwrap();
break;
}
_ => {}
}
}
c.unregister_object_path("/hello");
});
let c = Connection::get_private(BusType::Session).unwrap();
let n = rx.recv().unwrap();
let m = Message::new_method_call(&n, "/hello", "com.example.hello", "Hello").unwrap();
println!("Sending...");
let r = c.send_with_reply_and_block(m, 8000).unwrap();
let reply = r.get_items();
println!("{:?}", reply);
thread.join().unwrap();
}
#[test]
fn register_name() {
let c = Connection::get_private(BusType::Session).unwrap();
let n = format!("com.example.hello.test.register_name");
assert_eq!(c.register_name(&n, NameFlag::ReplaceExisting as u32).unwrap(), RequestNameReply::PrimaryOwner);
assert_eq!(c.release_name(&n).unwrap(), ReleaseNameReply::Released);
}
#[test]
fn signal() {
let c = Connection::get_private(BusType::Session).unwrap();
let iface = "com.example.signaltest";
let mstr = format!("interface='{}',member='ThisIsASignal'", iface);
c.add_match(&mstr).unwrap();
let m = Message::new_signal("/mysignal", iface, "ThisIsASignal").unwrap();
let uname = c.unique_name();
c.send(m).unwrap();
for n in c.iter(1000) {
match n {
ConnectionItem::Signal(s) => {
let (_, p, i, m) = s.headers();
match (&*p.unwrap(), &*i.unwrap(), &*m.unwrap()) {
("/mysignal", "com.example.signaltest", "ThisIsASignal") => {
assert_eq!(&*s.sender().unwrap(), &*uname);
break;
},
(_, _, _) => println!("Other signal: {:?}", s.headers()),
}
}
_ => {},
}
}
c.remove_match(&mstr).unwrap();
}
#[test]
fn watch() {
let c = Connection::get_private(BusType::Session).unwrap();
let d = c.watch_fds();
assert!(d.len() > 0);
println!("Fds to watch: {:?}", d);
}
}

1154
third_party/rust/dbus/src/message.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1058
third_party/rust/dbus/src/methoddisp.rs vendored Normal file

File diff suppressed because it is too large Load Diff

553
third_party/rust/dbus/src/objpath.rs vendored Normal file
View File

@ -0,0 +1,553 @@
#![allow(deprecated)]
use super::{Connection, Message, MessageItem, Error, TypeSig};
use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use std::borrow::Cow;
/// a Method has a list of Arguments.
pub struct Argument<'a> {
name: &'a str,
sig: TypeSig<'a>,
}
impl<'a> Argument<'a> {
/// Create a new Argument.
pub fn new<T: Into<Cow<'a, str>>>(name: &'a str, sig: T) -> Argument<'a> {
Argument { name: name, sig: sig.into() }
}
}
struct Annotation {
name: String,
value: String,
}
struct ISignal<'a> {
args: Vec<Argument<'a>>,
anns: Vec<Annotation>,
}
/// Declares that an Interface can send this signal
pub struct Signal<'a> {
name: String,
i: ISignal<'a>,
}
impl<'a> Signal<'a> {
/// Create a new Signal.
pub fn new<N: ToString>(name: N, args: Vec<Argument<'a>>) -> Signal<'a> {
Signal { name: name.to_string(), i: ISignal { args: args, anns: vec![] } }
}
/// Add an Annotation to the Signal.
pub fn annotate<N: ToString, V: ToString>(&mut self, name: N, value: V) {
self.i.anns.push(Annotation { name: name.to_string(), value: value.to_string() });
}
}
/// A method returns either a list of MessageItems, or an error - the tuple
/// represents the name and message of the Error.
pub type MethodResult = Result<Vec<MessageItem>, (&'static str, String)>;
/// Contains the retrieved MessageItem or an error tuple containing the
/// name and message of the error.
pub type PropertyGetResult = Result<MessageItem, (&'static str, String)>;
/// Contains () or an error tuple containing the name and message of
/// the error.
pub type PropertySetResult = Result<(), (&'static str, String)>;
/// A boxed closure for dynamic dispatch. It is called when the method is
/// called by a remote application.
pub type MethodHandler<'a> = Box<FnMut(&mut Message) -> MethodResult + 'a>;
struct IMethod<'a> {
in_args: Vec<Argument<'a>>,
out_args: Vec<Argument<'a>>,
cb: Rc<RefCell<MethodHandler<'a>>>,
anns: Vec<Annotation>,
}
/// a method that can be called from another application
pub struct Method<'a> {
name: String,
i: IMethod<'a>
}
impl<'a> Method<'a> {
/// Create a new Method.
#[deprecated(note="please use `tree` module instead")]
pub fn new<N: ToString>(name: N, in_args: Vec<Argument<'a>>,
out_args: Vec<Argument<'a>>, cb: MethodHandler<'a>) -> Method<'a> {
Method { name: name.to_string(), i: IMethod {
in_args: in_args, out_args: out_args, cb: Rc::new(RefCell::new(cb)), anns: vec![] }
}
}
/// Add an Annotation to the Method.
pub fn annotate<N: ToString, V: ToString>(&mut self, name: N, value: V) {
self.i.anns.push(Annotation { name: name.to_string(), value: value.to_string() });
}
}
/// A read/write property handler.
pub trait PropertyRWHandler {
/// Get a property's value.
fn get(&self) -> PropertyGetResult;
/// Set a property's value.
fn set(&self, &MessageItem) -> PropertySetResult;
}
/// A read-only property handler.
pub trait PropertyROHandler {
/// Get a property's value.
fn get(&self) -> PropertyGetResult;
}
/// A write-only property handler.
pub trait PropertyWOHandler {
/// Set a property's value.
fn set(&self, &MessageItem) -> PropertySetResult;
}
/// Types of access to a Property.
pub enum PropertyAccess<'a> {
RO(Box<PropertyROHandler+'a>),
RW(Box<PropertyRWHandler+'a>),
WO(Box<PropertyWOHandler+'a>),
}
struct IProperty<'a> {
sig: TypeSig<'a>,
access: PropertyAccess<'a>,
anns: Vec<Annotation>,
}
/// Properties that a remote application can get/set.
pub struct Property<'a> {
name: String,
i: IProperty<'a>
}
impl<'a> Property<'a> {
fn new<N: ToString>(name: N, sig: TypeSig<'a>, a: PropertyAccess<'a>) -> Property<'a> {
Property { name: name.to_string(), i: IProperty { sig: sig, access: a, anns: vec![] } }
}
/// Creates a new read-only Property
pub fn new_ro<N: ToString>(name: N, sig: TypeSig<'a>, h: Box<PropertyROHandler+'a>) -> Property<'a> {
Property::new(name, sig, PropertyAccess::RO(h))
}
/// Creates a new read-write Property
pub fn new_rw<N: ToString>(name: N, sig: TypeSig<'a>, h: Box<PropertyRWHandler+'a>) -> Property<'a> {
Property::new(name, sig, PropertyAccess::RW(h))
}
/// Creates a new write-only Property
pub fn new_wo<N: ToString>(name: N, sig: TypeSig<'a>, h: Box<PropertyWOHandler+'a>) -> Property<'a> {
Property::new(name, sig, PropertyAccess::WO(h))
}
/// Add an annotation to the Property
pub fn annotate<N: ToString, V: ToString>(&mut self, name: N, value: V) {
self.i.anns.push(Annotation { name: name.to_string(), value: value.to_string() })
}
}
/// Interfaces can contain Methods, Properties, and Signals.
pub struct Interface<'a> {
methods: BTreeMap<String, IMethod<'a>>,
properties: BTreeMap<String, IProperty<'a>>,
signals: BTreeMap<String, ISignal<'a>>,
}
impl<'a> Interface<'a> {
/// Create a new Interface.
#[deprecated(note="please use `tree` module instead")]
pub fn new(m: Vec<Method<'a>>, p: Vec<Property<'a>>, s: Vec<Signal<'a>>) -> Interface<'a> {
Interface {
methods: m.into_iter().map(|m| (m.name, m.i)).collect(),
properties: p.into_iter().map(|p| (p.name, p.i)).collect(),
signals: s.into_iter().map(|s| (s.name, s.i)).collect(),
}
}
}
struct IObjectPath<'a> {
conn: &'a Connection,
path: String,
registered: Cell<bool>,
interfaces: RefCell<BTreeMap<String, Interface<'a>>>,
}
/// Represents a D-Bus object path, which can in turn contain Interfaces.
pub struct ObjectPath<'a> {
// We need extra references for the introspector and property handlers, hence this extra boxing
i: Rc<IObjectPath<'a>>,
}
impl<'a> Drop for ObjectPath<'a> {
fn drop(&mut self) {
let _ = self.i.set_registered(false);
self.i.interfaces.borrow_mut().clear(); // This should remove all the other references to i
}
}
fn introspect_args(args: &Vec<Argument>, indent: &str, dir: &str) -> String {
args.iter().fold("".to_string(), |aa, az| {
format!("{}{}<arg name=\"{}\" type=\"{}\"{}/>\n", aa, indent, az.name, az.sig, dir)
})
}
fn introspect_anns(anns: &Vec<Annotation>, indent: &str) -> String {
anns.iter().fold("".to_string(), |aa, az| {
format!("{}{}<annotation name=\"{}\" value=\"{}\"/>\n", aa, indent, az.name, az.value)
})
}
fn introspect_map<T, C: Fn(&T) -> (String, String)>
(h: &BTreeMap<String, T>, name: &str, indent: &str, func: C) -> String {
h.iter().fold("".to_string(), |a, (k, v)| {
let (params, contents) = func(v);
format!("{}{}<{} name=\"{}\"{}{}>\n",
a, indent, name, k, params, if contents.len() > 0 {
format!(">\n{}{}</{}", contents, indent, name)
}
else { format!("/") }
)
})
}
impl<'a> IObjectPath<'a> {
fn set_registered(&self, register: bool) -> Result<(), Error> {
if register == self.registered.get() { return Ok(()) };
if register {
try!(self.conn.register_object_path(&self.path));
} else {
self.conn.unregister_object_path(&self.path);
}
self.registered.set(register);
Ok(())
}
fn introspect(&self, _: &mut Message) -> MethodResult {
let ifacestr = introspect_map(&self.interfaces.borrow(), "interface", " ", |iv|
(format!(""), format!("{}{}{}",
introspect_map(&iv.methods, "method", " ", |m| (format!(""), format!("{}{}{}",
introspect_args(&m.in_args, " ", " direction=\"in\""),
introspect_args(&m.out_args, " ", " direction=\"out\""),
introspect_anns(&m.anns, " ")
))),
introspect_map(&iv.properties, "property", " ", |p| (
format!(" type=\"{}\" access=\"{}\"", p.sig, match p.access {
PropertyAccess::RO(_) => "read",
PropertyAccess::RW(_) => "readwrite",
PropertyAccess::WO(_) => "write",
}),
introspect_anns(&p.anns, " ")
)),
introspect_map(&iv.signals, "signal", " ", |s| (format!(""), format!("{}{}",
introspect_args(&s.args, " ", ""),
introspect_anns(&s.anns, " ")
)))
))
);
let childstr = self.conn.list_registered_object_paths(&self.path).iter().fold("".to_string(), |na, n|
format!(r##"{} <node name="{}"/>
"##, na, n)
);
let nodestr = format!(r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="{}">
{}{}</node>"##, self.path, ifacestr, childstr);
Ok(vec!(MessageItem::Str(nodestr)))
}
fn property_get(&self, msg: &mut Message) -> MethodResult {
let items = msg.get_items();
let iface_name = try!(parse_msg_str(items.get(0)));
let prop_name = try!(parse_msg_str(items.get(1)));
let is = self.interfaces.borrow();
let i = try!(is.get(iface_name).ok_or_else(||
("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", iface_name))));
let p = try!(i.properties.get(prop_name).ok_or_else(||
("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", prop_name))));
let v = try!(match p.access {
PropertyAccess::RO(ref cb) => cb.get(),
PropertyAccess::RW(ref cb) => cb.get(),
PropertyAccess::WO(_) => {
return Err(("org.freedesktop.DBus.Error.Failed", format!("Property {} is write only", prop_name)))
}
});
Ok(vec!(MessageItem::Variant(Box::new(v))))
}
fn property_getall(&self, msg: &mut Message) -> MethodResult {
let items = msg.get_items();
let iface_name = try!(parse_msg_str(items.get(0)));
let is = self.interfaces.borrow();
let i = try!(is.get(iface_name).ok_or_else(||
("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", iface_name))));
let mut result = Vec::new();
result.push(try!(MessageItem::from_dict(i.properties.iter().filter_map(|(pname, pv)| {
let v = match pv.access {
PropertyAccess::RO(ref cb) => cb.get(),
PropertyAccess::RW(ref cb) => cb.get(),
PropertyAccess::WO(_) => { return None }
};
Some(v.map(|vv| (pname.clone(),vv)))
}))));
Ok(result)
}
fn property_set(&self, msg: &mut Message) -> MethodResult {
let items = msg.get_items();
let iface_name = try!(parse_msg_str(items.get(0)));
let prop_name = try!(parse_msg_str(items.get(1)));
let value = try!(parse_msg_variant(items.get(2)));
let is = self.interfaces.borrow();
let i = try!(is.get(iface_name).ok_or_else(||
("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", iface_name))));
let p = try!(i.properties.get(prop_name).ok_or_else(||
("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", prop_name))));
try!(match p.access {
PropertyAccess::WO(ref cb) => cb.set(value),
PropertyAccess::RW(ref cb) => cb.set(value),
PropertyAccess::RO(_) => {
return Err(("org.freedesktop.DBus.Error.PropertyReadOnly", format!("Property {} is read only", prop_name)))
}
});
Ok(vec!())
}
}
fn parse_msg_str(a: Option<&MessageItem>) -> Result<&str,(&'static str, String)> {
let name = try!(a.ok_or_else(|| ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a))));
name.inner().map_err(|_| ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)))
}
fn parse_msg_variant(a: Option<&MessageItem>) -> Result<&MessageItem,(&'static str, String)> {
let name = try!(a.ok_or_else(|| ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a))));
name.inner().map_err(|_| ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)))
}
impl PropertyROHandler for MessageItem {
fn get(&self) -> PropertyGetResult {
Ok(self.clone())
}
}
impl<'a> ObjectPath<'a> {
/// Create a new ObjectPath.
#[deprecated(note="please use `tree` module instead")]
pub fn new(conn: &'a Connection, path: &str, introspectable: bool) -> ObjectPath<'a> {
let i = IObjectPath {
conn: conn,
path: path.to_string(),
registered: Cell::new(false),
interfaces: RefCell::new(BTreeMap::new()),
};
let mut o = ObjectPath { i: Rc::new(i) };
if introspectable {
let o_cl = o.i.clone();
let i = Interface::new(vec!(
Method::new("Introspect", vec!(), vec!(Argument::new("xml_data", "s")),
Box::new(move |m| { o_cl.introspect(m) }))), vec!(), vec!());
o.insert_interface("org.freedesktop.DBus.Introspectable", i);
}
o
}
fn add_property_handler(&mut self) {
if self.i.interfaces.borrow().contains_key("org.freedesktop.DBus.Properties") { return };
let (cl1, cl2, cl3) = (self.i.clone(), self.i.clone(), self.i.clone());
let i = Interface::new(vec!(
Method::new("Get",
vec!(Argument::new("interface_name", "s"), Argument::new("property_name", "s")),
vec!(Argument::new("value", "v")),
Box::new(move |m| cl1.property_get(m))),
Method::new("GetAll",
vec!(Argument::new("interface_name", "s")),
vec!(Argument::new("props", "a{sv}")),
Box::new(move |m| cl2.property_getall(m))),
Method::new("Set",
vec!(Argument::new("interface_name", "s"), Argument::new("property_name", "s"),
Argument::new("value", "v")),
vec!(),
Box::new(move |m| cl3.property_set(m)))),
vec!(), vec!());
self.insert_interface("org.freedesktop.DBus.Properties", i);
}
/// Add an Interface to this ObjectPath.
pub fn insert_interface<N: ToString>(&mut self, name: N, i: Interface<'a>) {
if !i.properties.is_empty() {
self.add_property_handler();
}
self.i.interfaces.borrow_mut().insert(name.to_string(), i);
}
/// Returns if the ObjectPath is registered.
pub fn is_registered(&self) -> bool {
self.i.registered.get()
}
/// Changes the registration status of the ObjectPath.
pub fn set_registered(&mut self, register: bool) -> Result<(), Error> {
self.i.set_registered(register)
}
/// Handles a method call if the object path matches.
/// Return value: None => not handled (no match),
/// Some(Err(())) => message reply send failed,
/// Some(Ok()) => message reply send ok */
pub fn handle_message(&mut self, msg: &mut Message) -> Option<Result<(), ()>> {
let (_, path, iface, method) = msg.headers();
if path.is_none() || path.unwrap() != self.i.path { return None; }
if iface.is_none() { return None; }
let method = {
// This is because we don't want to hold the refcell lock when we call the
// callback - maximum flexibility for clients.
if let Some(i) = self.i.interfaces.borrow().get(&iface.unwrap()) {
if let Some(Some(m)) = method.map(|m| i.methods.get(&m)) {
m.cb.clone()
} else {
return Some(self.i.conn.send(Message::new_error(
msg, "org.freedesktop.DBus.Error.UnknownMethod", "Unknown method").unwrap()).map(|_| ()));
}
} else {
return Some(self.i.conn.send(Message::new_error(msg,
"org.freedesktop.DBus.Error.UnknownInterface", "Unknown interface").unwrap()).map(|_| ()));
}
};
let r = {
// Now call it
let mut m = method.borrow_mut();
(&mut **m)(msg)
};
let reply = match r {
Ok(r) => {
let mut z = Message::new_method_return(msg).unwrap();
z.append_items(&r);
z
},
Err((aa,bb)) => Message::new_error(msg, aa, &bb).unwrap(),
};
Some(self.i.conn.send(reply).map(|_| ()))
}
}
#[cfg(test)]
fn make_objpath<'a>(c: &'a Connection) -> ObjectPath<'a> {
let mut o = ObjectPath::new(c, "/echo", true);
o.insert_interface("com.example.echo", Interface::new(
vec!(Method::new("Echo",
vec!(Argument::new("request", "s")),
vec!(Argument::new("reply", "s")), Box::new(|_| { Err(("dummy", "dummy".to_string())) } ))),
vec!(Property::new_ro("EchoCount", MessageItem::Int32(7).type_sig(), Box::new(MessageItem::Int32(7)))),
vec!(Signal::new("Echoed", vec!(Argument::new("data", "s"))))));
o
}
#[test]
fn test_objpath() {
let c = Connection::get_private(super::BusType::Session).unwrap();
let mut o = make_objpath(&c);
o.set_registered(true).unwrap();
let busname = format!("com.example.objpath.test.test_objpath");
assert_eq!(c.register_name(&busname, super::NameFlag::ReplaceExisting as u32).unwrap(), super::RequestNameReply::PrimaryOwner);
let thread = ::std::thread::spawn(move || {
let c = Connection::get_private(super::BusType::Session).unwrap();
let pr = super::Props::new(&c, &*busname, "/echo", "com.example.echo", 5000);
assert_eq!(pr.get("EchoCount").unwrap(), 7i32.into());
let m = pr.get_all().unwrap();
assert_eq!(m.get("EchoCount").unwrap(), &7i32.into());
});
let mut i = 0;
for n in c.iter(1000) {
println!("objpath msg {:?}", n);
if let super::ConnectionItem::MethodCall(mut m) = n {
if let Some(msg) = o.handle_message(&mut m) {
msg.unwrap();
i += 1;
if i >= 2 { break };
}
}
}
thread.join().unwrap();
}
/// Currently commented out because it requires feature(alloc)
/*
#[test]
fn test_refcount() {
let c = Connection::get_private(super::BusType::Session).unwrap();
let i = {
let o = make_objpath(&c);
o.i.clone()
};
assert!(::std::rc::is_unique(&i));
}
*/
#[test]
fn test_introspect() {
let c = Connection::get_private(super::BusType::Session).unwrap();
let mut o = make_objpath(&c);
o.set_registered(true).unwrap();
let mut o2 = ObjectPath::new(&c, "/echo/subpath", true);
o2.set_registered(true).unwrap();
let mut msg = Message::new_method_call("com.example.echoserver", "/echo", "org.freedesktop.DBus.Introspectable", "Introspect").unwrap();
println!("Introspect result: {}", parse_msg_str(o.i.introspect(&mut msg).unwrap().get(0)).unwrap());
let result = r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/echo">
<interface name="com.example.echo">
<method name="Echo">
<arg name="request" type="s" direction="in"/>
<arg name="reply" type="s" direction="out"/>
</method>
<property name="EchoCount" type="i" access="read"/>
<signal name="Echoed">
<arg name="data" type="s"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="xml_data" type="s" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface_name" type="s" direction="in"/>
<arg name="property_name" type="s" direction="in"/>
<arg name="value" type="v" direction="out"/>
</method>
<method name="GetAll">
<arg name="interface_name" type="s" direction="in"/>
<arg name="props" type="a{sv}" direction="out"/>
</method>
<method name="Set">
<arg name="interface_name" type="s" direction="in"/>
<arg name="property_name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
</interface>
<node name="subpath"/>
</node>"##;
assert_eq!(result, parse_msg_str(o.i.introspect(&mut msg).unwrap().get(0)).unwrap());
}

136
third_party/rust/dbus/src/prop.rs vendored Normal file
View File

@ -0,0 +1,136 @@
use super::{Connection, Message, MessageItem, Error, Path, Interface, BusName};
use std::collections::BTreeMap;
/// Client side properties - get and set properties on a remote application.
pub struct Props<'a> {
name: BusName<'a>,
path: Path<'a>,
interface: Interface<'a>,
timeout_ms: i32,
conn: &'a Connection,
}
impl<'a> Props<'a> {
/// Create a new Props.
pub fn new<N, P, I>(conn: &'a Connection, name: N, path: P, interface: I, timeout_ms: i32) -> Props<'a>
where N: Into<BusName<'a>>, P: Into<Path<'a>>, I: Into<Interface<'a>> {
Props {
name: name.into(),
path: path.into(),
interface: interface.into(),
timeout_ms: timeout_ms,
conn: conn,
}
}
/// Get a single property's value.
pub fn get(&self, propname: &str) -> Result<MessageItem, Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"Get".into());
m.append_items(&[self.interface.to_string().into(), propname.to_string().into()]);
let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
let reply = try!(r.as_result()).get_items();
if reply.len() == 1 {
if let &MessageItem::Variant(ref v) = &reply[0] {
return Ok((**v).clone())
}
}
let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply);
return Err(Error::new_custom("InvalidReply", &f));
}
/// Set a single property's value.
pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"Set".into());
m.append_items(&[self.interface.to_string().into(), propname.to_string().into(), Box::new(value).into()]);
let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
try!(r.as_result());
Ok(())
}
/// Get a map of all the properties' names and their values.
pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"GetAll".into());
m.append_items(&[self.interface.to_string().into()]);
let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
let reply = try!(r.as_result()).get_items();
(|| {
if reply.len() != 1 { return Err(()) };
let mut t = BTreeMap::new();
let a: &[MessageItem] = try!(reply[0].inner());
for p in a.iter() {
let (k, v) = try!(p.inner());
let (k, v): (&String, &MessageItem) = (try!(k.inner()), try!(v.inner()));
t.insert(k.clone(), v.clone());
}
Ok(t)
})().map_err(|_| {
let f = format!("Invalid reply for property GetAll: '{:?}'", reply);
Error::new_custom("InvalidReply", &f)
})
}
}
/// Wrapper around Props that keeps a map of fetched properties.
pub struct PropHandler<'a> {
p: Props<'a>,
map: BTreeMap<String, MessageItem>,
}
impl<'a> PropHandler<'a> {
/// Create a new PropHandler from a Props.
pub fn new(p: Props) -> PropHandler {
PropHandler { p: p, map: BTreeMap::new() }
}
/// Get a map of all the properties' names and their values.
pub fn get_all(&mut self) -> Result<(), Error> {
self.map = try!(self.p.get_all());
Ok(())
}
/// Get a mutable reference to the PropHandler's fetched properties.
pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map }
/// Get a reference to the PropHandler's fetched properties.
pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map }
/// Get a single property's value.
pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> {
let v = try!(self.p.get(propname));
self.map.insert(propname.to_string(), v);
Ok(self.map.get(propname).unwrap())
}
/// Set a single property's value.
pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> {
try!(self.p.set(propname, value.clone()));
self.map.insert(propname.to_string(), value);
Ok(())
}
}
/* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but PolicyKit should be around on most distros. */
#[test]
fn test_get_policykit_version() {
use super::BusType;
let c = Connection::get_private(BusType::System).unwrap();
let p = Props::new(&c, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority",
"org.freedesktop.PolicyKit1.Authority", 10000);
/* Let's use both the get and getall methods and see if we get the same result */
let v = p.get("BackendVersion").unwrap();
let vall = p.get_all().unwrap();
let v2 = vall.get("BackendVersion").unwrap();
assert_eq!(&v, &*v2);
match v {
MessageItem::Str(ref s) => { println!("Policykit Backend version is {}", s); }
_ => { panic!("Invalid Get: {:?}", v); }
};
}

96
third_party/rust/dbus/src/signalargs.rs vendored Normal file
View File

@ -0,0 +1,96 @@
use arg;
use {Message, MessageType, BusName, Path, Interface, Member};
/// Helper methods for structs representing a Signal
///
/// # Example
///
/// Listen to InterfacesRemoved signal from org.bluez.obex.
///
/// ```rust,no_run
/// use dbus::{Connection, BusType, SignalArgs};
/// use dbus::stdintf::org_freedesktop_dbus::ObjectManagerInterfacesRemoved as IR;
///
/// let c = Connection::get_private(BusType::Session).unwrap();
/// // Add a match for this signal
/// let mstr = IR::match_str(Some(&"org.bluez.obex".into()), None);
/// c.add_match(&mstr).unwrap();
///
/// // Wait for the signal to arrive.
/// for msg in c.incoming(1000) {
/// if let Some(ir) = IR::from_message(&msg) {
/// println!("Interfaces {:?} have been removed from bluez on path {}.", ir.interfaces, ir.object);
/// }
/// }
/// ```
pub trait SignalArgs: Default {
/// D-Bus name of signal
const NAME: &'static str;
/// D-Bus name of interface this signal belongs to
const INTERFACE: &'static str;
/// Low-level method for appending this struct to a message.
///
/// You're more likely to use one of the more high level functions.
fn append(&self, i: &mut arg::IterAppend);
/// Low-level method for getting arguments from a message.
///
/// You're more likely to use one of the more high level functions.
fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError>;
/// Returns a message that emits the signal.
fn to_emit_message(&self, path: &Path) -> Message {
let mut m = Message::signal(path, &Interface::from(Self::INTERFACE), &Member::from(Self::NAME));
self.append(&mut arg::IterAppend::new(&mut m));
m
}
/// If the message is a signal of the correct type, return its arguments, otherwise return None.
///
/// This does not check sender and path of the message, which is likely relevant to you as well.
fn from_message(m: &Message) -> Option<Self> {
if m.msg_type() != MessageType::Signal { None }
else if m.interface().as_ref().map(|x| &**x) != Some(Self::INTERFACE) { None }
else if m.member().as_ref().map(|x| &**x) != Some(Self::NAME) { None }
else {
let mut z: Self = Default::default();
z.get(&mut m.iter_init()).ok().map(|_| z)
}
}
/// Returns a string that can be sent to `Connection::add_match`.
///
/// If sender and/or path is None, matches all senders and/or paths.
fn match_str(sender: Option<&BusName>, path: Option<&Path>) -> String {
let mut r = format!("type='signal',interface='{}',member='{}'", Self::INTERFACE, Self::NAME);
sender.map(|s| r += &format!(",sender='{}'", s));
path.map(|s| r += &format!(",path='{}'", s));
r
}
}
#[test]
fn intf_removed() {
use {Connection, BusType};
use stdintf::org_freedesktop_dbus::ObjectManagerInterfacesRemoved as IR;
let c = Connection::get_private(BusType::Session).unwrap();
let mstr = IR::match_str(Some(&c.unique_name().into()), Some(&"/hello".into()));
println!("Match str: {}", mstr);
c.add_match(&mstr).unwrap();
let ir = IR { object: "/hello".into(), interfaces: vec!("ABC.DEF".into(), "GHI.JKL".into()) };
let cp = c.with_path("dbus.dummy", "/hello", 2000);
cp.emit(&ir).unwrap();
for msg in c.incoming(1000) {
if &*msg.sender().unwrap() != &*c.unique_name() { continue; }
if let Some(ir2) = IR::from_message(&msg) {
assert_eq!(ir2.object, ir.object);
assert_eq!(ir2.interfaces, ir.interfaces);
break;
}
}
}

212
third_party/rust/dbus/src/stdintf.rs vendored Normal file
View File

@ -0,0 +1,212 @@
//! This module contains some standard interfaces and an easy way to call them.
//!
//! See the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces) for more information about these standard interfaces.
//!
//! The code here was originally created by dbus-codegen.
//!
//! # Example
//! ```
//! use dbus::{Connection, BusType};
//! use dbus::stdintf::org_freedesktop_dbus::Introspectable;
//! let c = Connection::get_private(BusType::Session).unwrap();
//! let p = c.with_path("org.freedesktop.DBus", "/", 10000);
//! println!("Introspection XML: {}", p.introspect().unwrap());
//! ```
//!
#![allow(missing_docs)]
pub use self::org_freedesktop_dbus::Peer as OrgFreedesktopDBusPeer;
pub use self::org_freedesktop_dbus::Introspectable as OrgFreedesktopDBusIntrospectable;
pub use self::org_freedesktop_dbus::Properties as OrgFreedesktopDBusProperties;
pub use self::org_freedesktop_dbus::ObjectManager as OrgFreedesktopDBusObjectManager;
pub mod org_freedesktop_dbus {
use arg;
/// Method of the [org.freedesktop.DBus.Introspectable](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable) interface.
pub trait Introspectable {
type Err;
fn introspect(&self) -> Result<String, Self::Err>;
}
impl<'a, C: ::std::ops::Deref<Target=::Connection>> Introspectable for ::ConnPath<'a, C> {
type Err = ::Error;
fn introspect(&self) -> Result<String, Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Introspectable".into(), &"Introspect".into(), |_| {
}));
try!(m.as_result());
let mut i = m.iter_init();
let xml: String = try!(i.read());
Ok(xml)
}
}
/// Methods of the [org.freedesktop.DBus.Properties](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties) interface.
pub trait Properties {
type Err;
fn get<R0: for<'b> arg::Get<'b>>(&self, interface_name: &str, property_name: &str) -> Result<R0, Self::Err>;
fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err>;
fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), Self::Err>;
}
impl<'a, C: ::std::ops::Deref<Target=::Connection>> Properties for ::ConnPath<'a, C> {
type Err = ::Error;
fn get<R0: for<'b> arg::Get<'b>>(&self, interface_name: &str, property_name: &str) -> Result<R0, Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Get".into(), |msg| {
let mut i = arg::IterAppend::new(msg);
i.append(interface_name);
i.append(property_name);
}));
try!(m.as_result());
let mut i = m.iter_init();
let value: arg::Variant<R0> = try!(i.read());
Ok(value.0)
}
fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"GetAll".into(), |msg| {
let mut i = arg::IterAppend::new(msg);
i.append(interface_name);
}));
try!(m.as_result());
let mut i = m.iter_init();
let properties: ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>> = try!(i.read());
Ok(properties)
}
fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Set".into(), |msg| {
let mut i = arg::IterAppend::new(msg);
i.append(interface_name);
i.append(property_name);
i.append(arg::Variant(value));
}));
try!(m.as_result());
Ok(())
}
}
#[derive(Debug, Default)]
/// Struct to send/receive the PropertiesChanged signal of the
/// [org.freedesktop.DBus.Properties](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties) interface.
pub struct PropertiesPropertiesChanged {
pub interface_name: String,
pub changed_properties: ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>,
pub invalidated_properties: Vec<String>,
}
impl ::SignalArgs for PropertiesPropertiesChanged {
const NAME: &'static str = "PropertiesChanged";
const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
fn append(&self, i: &mut arg::IterAppend) {
(&self.interface_name as &arg::RefArg).append(i);
(&self.changed_properties as &arg::RefArg).append(i);
(&self.invalidated_properties as &arg::RefArg).append(i);
}
fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
self.interface_name = try!(i.read());
self.changed_properties = try!(i.read());
self.invalidated_properties = try!(i.read());
Ok(())
}
}
/// Method of the [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub trait ObjectManager {
type Err;
fn get_managed_objects(&self) -> Result<::std::collections::HashMap<::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err>;
}
impl<'a, C: ::std::ops::Deref<Target=::Connection>> ObjectManager for ::ConnPath<'a, C> {
type Err = ::Error;
fn get_managed_objects(&self) -> Result<::std::collections::HashMap<::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.ObjectManager".into(), &"GetManagedObjects".into(), |_| {
}));
try!(m.as_result());
let mut i = m.iter_init();
let objects: ::std::collections::HashMap<::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>> = try!(i.read());
Ok(objects)
}
}
#[derive(Debug, Default)]
/// Struct to send/receive the InterfacesAdded signal of the
/// [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub struct ObjectManagerInterfacesAdded {
pub object: ::Path<'static>,
pub interfaces: ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>,
}
impl ::SignalArgs for ObjectManagerInterfacesAdded {
const NAME: &'static str = "InterfacesAdded";
const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
fn append(&self, i: &mut arg::IterAppend) {
(&self.object as &arg::RefArg).append(i);
(&self.interfaces as &arg::RefArg).append(i);
}
fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
self.object = try!(i.read());
self.interfaces = try!(i.read());
Ok(())
}
}
#[derive(Debug, Default)]
/// Struct to send/receive the InterfacesRemoved signal of the
/// [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub struct ObjectManagerInterfacesRemoved {
pub object: ::Path<'static>,
pub interfaces: Vec<String>,
}
impl ::SignalArgs for ObjectManagerInterfacesRemoved {
const NAME: &'static str = "InterfacesRemoved";
const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
fn append(&self, i: &mut arg::IterAppend) {
(&self.object as &arg::RefArg).append(i);
(&self.interfaces as &arg::RefArg).append(i);
}
fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
self.object = try!(i.read());
self.interfaces = try!(i.read());
Ok(())
}
}
/// Methods of the [org.freedesktop.DBus.Peer](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer) interface.
pub trait Peer {
type Err;
fn ping(&self) -> Result<(), Self::Err>;
fn get_machine_id(&self) -> Result<String, Self::Err>;
}
impl<'a, C: ::std::ops::Deref<Target=::Connection>> Peer for ::ConnPath<'a, C> {
type Err = ::Error;
fn ping(&self) -> Result<(), Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"Ping".into(), |_| {
}));
try!(m.as_result());
Ok(())
}
fn get_machine_id(&self) -> Result<String, Self::Err> {
let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"GetMachineId".into(), |_| {
}));
try!(m.as_result());
let mut i = m.iter_init();
let machine_uuid: String = try!(i.read());
Ok(machine_uuid)
}
}
}

210
third_party/rust/dbus/src/strings.rs vendored Normal file
View File

@ -0,0 +1,210 @@
// CString wrappers.
use std::{str, fmt, ops, default, hash};
use std::ffi::{CStr, CString};
use std::borrow::{Borrow, Cow};
use std::os::raw::c_char;
#[cfg(not(feature = "no-string-validation"))]
use Error;
#[cfg(not(feature = "no-string-validation"))]
use ffi;
macro_rules! cstring_wrapper {
($t: ident, $s: ident) => {
impl<'m> $t<'m> {
#[cfg(feature = "no-string-validation")]
fn check_valid(_: *const c_char) -> Result<(), String> { Ok(()) }
#[cfg(not(feature = "no-string-validation"))]
fn check_valid(c: *const c_char) -> Result<(), String> {
let mut e = Error::empty();
let b = unsafe { ffi::$s(c, e.get_mut()) };
if b != 0 { Ok(()) } else { Err(e.message().unwrap().into()) }
}
/// Creates a new instance of this struct.
///
/// Note: If the no-string-validation feature is activated, this string
/// will not be checked for conformance with the D-Bus specification.
pub fn new<S: Into<Vec<u8>>>(s: S) -> Result<$t<'m>, String> {
let c = try!(CString::new(s).map_err(|e| e.to_string()));
$t::check_valid(c.as_ptr()).map(|_| $t(Cow::Owned(c)))
}
/// Creates a new instance of this struct. If you end it with \0,
/// it can borrow the slice without extra allocation.
///
/// Note: If the no-string-validation feature is activated, this string
/// will not be checked for conformance with the D-Bus specification.
pub fn from_slice(s: &'m [u8]) -> Result<$t<'m>, String> {
if s.len() == 0 || s[s.len()-1] != 0 { return $t::new(s) };
$t::check_valid(s.as_ptr() as *const c_char).map(|_| {
let c = unsafe { CStr::from_ptr(s.as_ptr() as *const c_char) };
$t(Cow::Borrowed(c))
})
}
/// This function creates a new instance of this struct, without checking.
/// It's up to you to guarantee that s ends with a \0 and is valid.
pub unsafe fn from_slice_unchecked(s: &'m [u8]) -> $t<'m> {
debug_assert!(s[s.len()-1] == 0);
$t(Cow::Borrowed(CStr::from_ptr(s.as_ptr() as *const c_char)))
}
/// View this struct as a CStr.
pub fn as_cstr(&self) -> &CStr { &self.0 }
/// Makes sure this string does not contain borrows.
pub fn into_static(self) -> $t<'static> {
$t(Cow::Owned(self.0.into_owned()))
}
}
/*
/// #Panics
///
/// If given string is not valid.
/// impl<S: Into<Vec<u8>>> From<S> for $t { fn from(s: S) -> $t { $t::new(s).unwrap() } }
*/
/// #Panics
///
/// If given string is not valid.
impl<'m> From<String> for $t<'m> { fn from(s: String) -> $t<'m> { $t::new(s).unwrap() } }
/// #Panics
///
/// If given string is not valid.
impl<'m> From<&'m String> for $t<'m> { fn from(s: &'m String) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
/// #Panics
///
/// If given string is not valid.
impl<'m> From<&'m str> for $t<'m> { fn from(s: &'m str) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
/// #Panics
///
/// If given string is not valid.
impl<'m> From<Cow<'m, str>> for $t<'m> {
fn from(s: Cow<'m, str>) -> $t<'m> {
match s {
Cow::Borrowed(z) => z.into(),
Cow::Owned(z) => z.into(),
}
}
}
impl<'inner, 'm: 'inner> From<&'m $t<'inner>> for $t<'m> {
fn from(borrow: &'m $t<'inner>) -> $t<'m> {
$t(Cow::Borrowed(borrow.0.borrow()))
}
}
impl<'m> ops::Deref for $t<'m> {
type Target = str;
fn deref(&self) -> &str { str::from_utf8(self.0.to_bytes()).unwrap() }
}
impl<'m> fmt::Display for $t<'m> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s: &str = &self;
(&s as &fmt::Display).fmt(f)
}
}
impl<'m> AsRef<CStr> for $t<'m> {
fn as_ref(&self) -> &CStr { &self.0 }
}
impl<'m> hash::Hash for $t<'m> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
}}
/// A wrapper around a string that is guaranteed to be
/// a valid (single) D-Bus type signature. Supersedes TypeSig.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Signature<'a>(Cow<'a, CStr>);
cstring_wrapper!(Signature, dbus_signature_validate_single);
impl Signature<'static> {
/// Makes a D-Bus signature that corresponds to A.
pub fn make<A: super::arg::Arg>() -> Signature<'static> { A::signature() }
}
/// A wrapper around a string that is guaranteed to be
/// a valid D-Bus object path.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Path<'a>(Cow<'a, CStr>);
cstring_wrapper!(Path, dbus_validate_path);
// This is needed so one can make arrays of paths easily
impl<'a> default::Default for Path<'a> {
fn default() -> Path<'a> { Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/\0".as_ptr() as *const c_char)})) }
}
/// A wrapper around a string that is guaranteed to be
/// a valid D-Bus member, i e, a signal or method name.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Member<'a>(Cow<'a, CStr>);
cstring_wrapper!(Member, dbus_validate_member);
/// A wrapper around a string that is guaranteed to be
/// a valid D-Bus interface name.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Interface<'a>(Cow<'a, CStr>);
cstring_wrapper!(Interface, dbus_validate_interface);
/// A wrapper around a string that is guaranteed to be
/// a valid D-Bus bus name.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct BusName<'a>(Cow<'a, CStr>);
cstring_wrapper!(BusName, dbus_validate_bus_name);
/// A wrapper around a string that is guaranteed to be
/// a valid D-Bus bus name.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct ErrorName<'a>(Cow<'a, CStr>);
cstring_wrapper!(ErrorName, dbus_validate_error_name);
#[test]
fn some_path() {
use std::os::raw::c_char;
let p1: Path = "/valid".into();
let p2 = Path::new("##invalid##");
assert_eq!(p1, Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/valid\0".as_ptr() as *const c_char) })));
#[cfg(not(feature = "no-string-validation"))]
assert_eq!(p2, Err("Object path was not valid: '##invalid##'".into()));
#[cfg(feature = "no-string-validation")]
assert_eq!(p2, Ok(Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"##invalid##\0".as_ptr() as *const c_char) }))));
}
#[test]
fn reborrow_path() {
let p1 = Path::from("/valid");
let p2 = p1.clone();
{
let p2_borrow: &Path = &p2;
let p3 = Path::from(p2_borrow);
// Check path created from borrow
assert_eq!(p2, p3);
}
// Check path that was previously borrowed
assert_eq!(p1, p2);
}
#[test]
fn make_sig() {
assert_eq!(&*Signature::make::<(&str, u8)>(), "(sy)");
}

View File

@ -0,0 +1,137 @@
use super::{MethodType, DataType, MTFn, MTFnMut, MTSync, MethodResult, MethodInfo};
use super::{Tree, ObjectPath, Interface, Property, Signal, Method};
use super::objectpath::IfaceCache;
use std::sync::Arc;
use Interface as IfaceName;
use {Member, Path, arg};
use std::cell::RefCell;
/// The factory is used to create object paths, interfaces, methods etc.
///
/// There are three factories:
///
/// **MTFn** - all methods are `Fn()`.
///
/// **MTFnMut** - all methods are `FnMut()`. This means they can mutate their environment,
/// which has the side effect that if you call it recursively, it will RefCell panic.
///
/// **MTSync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods
/// can be called from different threads in parallel.
///
#[derive(Debug, Clone)]
pub struct Factory<M: MethodType<D>, D: DataType=()>(Arc<IfaceCache<M, D>>);
impl<M: MethodType<D>, D: DataType> From<Arc<IfaceCache<M, D>>> for Factory<M, D> {
fn from(f: Arc<IfaceCache<M, D>>) -> Self { Factory(f) }
}
impl Factory<MTFn<()>, ()> {
/// Creates a new factory for single-thread use.
pub fn new_fn<D: DataType>() -> Factory<MTFn<D>, D> { Factory(IfaceCache::new()) }
/// Creates a new factory for single-thread use, where callbacks can mutate their environment.
pub fn new_fnmut<D: DataType>() -> Factory<MTFnMut<D>, D> { Factory(IfaceCache::new()) }
/// Creates a new factory for multi-thread use.
pub fn new_sync<D: DataType>() -> Factory<MTSync<D>, D> { Factory(IfaceCache::new()) }
}
impl<D: DataType> Factory<MTFn<D>, D> {
/// Creates a new method for single-thread use.
pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFn<D>, D>
where H: 'static + Fn(&MethodInfo<MTFn<D>, D>) -> MethodResult, T: Into<Member<'static>> {
super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
}
}
impl<D: DataType> Factory<MTFnMut<D>, D> {
/// Creates a new method for single-thread use.
pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFnMut<D>, D>
where H: 'static + FnMut(&MethodInfo<MTFnMut<D>, D>) -> MethodResult, T: Into<Member<'static>> {
super::leaves::new_method(t.into(), data, Box::new(RefCell::new(handler)) as Box<_>)
}
}
impl<D: DataType> Factory<MTSync<D>, D> {
/// Creates a new method for multi-thread use.
pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTSync<D>, D>
where H: Fn(&MethodInfo<MTSync<D>, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
}
}
impl<M: MethodType<D>, D: DataType> Factory<M, D> {
/// Creates a new property.
///
/// `A` is used to calculate the type signature of the property.
pub fn property<A: arg::Arg, T: Into<String>>(&self, name: T, data: D::Property) -> Property<M, D> {
let sig = A::signature();
super::leaves::new_property(name.into(), sig, data)
}
/// Creates a new signal.
pub fn signal<T: Into<Member<'static>>>(&self, name: T, data: D::Signal) -> Signal<D> {
super::leaves::new_signal(name.into(), data)
}
/// Creates a new interface.
pub fn interface<T: Into<IfaceName<'static>>>(&self, name: T, data: D::Interface) -> Interface<M, D> {
super::objectpath::new_interface(name.into(), data)
}
/// Creates a new object path.
pub fn object_path<T: Into<Path<'static>>>(&self, name: T, data: D::ObjectPath) -> ObjectPath<M, D> {
super::objectpath::new_objectpath(name.into(), data, self.0.clone())
}
/// Creates a new tree.
pub fn tree(&self, data: D::Tree) -> Tree<M, D> {
super::objectpath::new_tree(data)
}
/// Creates a new method - usually you'll use "method" instead.
///
/// This is useful for being able to create methods in code which is generic over methodtype.
pub fn method_sync<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<M, D>
where H: Fn(&MethodInfo<M, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
super::leaves::new_method(t.into(), data, M::make_method(handler))
}
}
#[test]
fn create_fnmut() {
let f = Factory::new_fnmut::<()>();
let mut move_me = 5u32;
let m = f.method("test", (), move |m| {
move_me += 1;
Ok(vec!(m.msg.method_return().append1(&move_me)))
});
assert_eq!(&**m.get_name(), "test");
}
#[test]
fn fn_customdata() {
#[derive(Default)]
struct Custom;
impl DataType for Custom {
type Tree = ();
type ObjectPath = Arc<u8>;
type Interface = ();
type Property = ();
type Method = i32;
type Signal = ();
}
let f = Factory::new_fn::<Custom>();
let m = f.method("test", 789, |_| unimplemented!());
assert_eq!(*m.get_data(), 789);
let o = f.object_path("/test/test", Arc::new(7));
assert_eq!(**o.get_data(), 7);
}

653
third_party/rust/dbus/src/tree/leaves.rs vendored Normal file
View File

@ -0,0 +1,653 @@
// Methods, signals, properties, and interfaces.
use super::utils::{Argument, Annotations, Introspect, introspect_args};
use super::{MethodType, MethodInfo, MethodResult, MethodErr, DataType, PropInfo, MTFn, MTFnMut, MTSync};
use {Member, Signature, Message, Path, MessageItem};
use Interface as IfaceName;
use arg;
use std::fmt;
use std::cell::RefCell;
use stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
// Workaround for https://github.com/rust-lang/rust/issues/31518
struct DebugMethod<M: MethodType<D>, D: DataType>(Box<M::Method>);
impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugMethod<M, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Method>") }
}
struct DebugGetProp<M: MethodType<D>, D: DataType>(Box<M::GetProp>);
impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugGetProp<M, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<GetProp>") }
}
struct DebugSetProp<M: MethodType<D>, D: DataType>(Box<M::SetProp>);
impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugSetProp<M, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<SetProp>") }
}
#[derive(Debug)]
/// A D-Bus Method.
pub struct Method<M: MethodType<D>, D: DataType> {
cb: DebugMethod<M, D>,
data: D::Method,
name: Member<'static>,
i_args: Vec<Argument>,
o_args: Vec<Argument>,
anns: Annotations,
}
impl<M: MethodType<D>, D: DataType> Method<M, D> {
/// Builder method that adds an "in" Argument to this Method.
pub fn in_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.i_args.push(a.into()); self }
/// Builder method that adds an "in" Argument to this Method.
pub fn inarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.i_args.push((s.into(), A::signature()).into()); self }
/// Builder method that adds multiple "in" Arguments to this Method.
pub fn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
self.i_args.extend(a.into_iter().map(|b| b.into())); self
}
/// Builder method that adds an "out" Argument to this Method.
pub fn out_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.o_args.push(a.into()); self }
/// Builder method that adds an "out" Argument to this Method.
pub fn outarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.o_args.push((s.into(), A::signature()).into()); self }
/// Builder method that adds multiple "out" Arguments to this Method.
pub fn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
self.o_args.extend(a.into_iter().map(|b| b.into())); self
}
/// Builder method that adds an annotation to the method.
pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
self.anns.insert(name, value); self
}
/// Builder method that adds an annotation that this entity is deprecated.
pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Call the Method
pub fn call(&self, minfo: &MethodInfo<M, D>) -> MethodResult { M::call_method(&self.cb.0, minfo) }
/// Get method name
pub fn get_name(&self) -> &Member<'static> { &self.name }
/// Get associated data
pub fn get_data(&self) -> &D::Method { &self.data }
}
impl<M: MethodType<D>, D: DataType> Introspect for Method<M, D> {
fn xml_name(&self) -> &'static str { "method" }
fn xml_params(&self) -> String { String::new() }
fn xml_contents(&self) -> String {
format!("{}{}{}",
introspect_args(&self.i_args, " ", " direction=\"in\""),
introspect_args(&self.o_args, " ", " direction=\"out\""),
self.anns.introspect(" "))
}
}
pub fn new_method<M: MethodType<D>, D: DataType>(n: Member<'static>, data: D::Method, cb: Box<M::Method>) -> Method<M, D> {
Method { name: n, i_args: vec!(), o_args: vec!(), anns: Annotations::new(), cb: DebugMethod(cb), data: data }
}
#[derive(Debug)]
/// A D-Bus Signal.
pub struct Signal<D: DataType> {
name: Member<'static>,
data: D::Signal,
arguments: Vec<Argument>,
anns: Annotations,
}
impl<D: DataType> Signal<D> {
/// Builder method that adds an Argument to the Signal.
pub fn arg<A: Into<Argument>>(mut self, a: A) -> Self { self.arguments.push(a.into()); self }
/// Builder method that adds an Argument to the Signal.
pub fn sarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.arguments.push((s.into(), A::signature()).into()); self }
/// Builder method that adds multiple Arguments to the Signal.
pub fn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
self.arguments.extend(a.into_iter().map(|b| b.into())); self
}
/// Add an annotation to this Signal.
pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
self.anns.insert(name, value); self
}
/// Add an annotation that this entity is deprecated.
pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Get signal name
pub fn get_name(&self) -> &Member<'static> { &self.name }
/// Get associated data
pub fn get_data(&self) -> &D::Signal { &self.data }
/// Returns a message which emits the signal when sent.
///
/// Same as "msg" but also takes a "MessageItem" argument.
pub fn emit(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[MessageItem]) -> Message {
let mut m = self.msg(p, i);
m.append_items(items);
m
}
/// Returns a message which emits the signal when sent.
///
/// Same as "emit" but does not take a "MessageItem" argument.
pub fn msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message {
Message::signal(p, i, &self.name)
}
}
impl<D: DataType> Introspect for Signal<D> {
fn xml_name(&self) -> &'static str { "signal" }
fn xml_params(&self) -> String { String::new() }
fn xml_contents(&self) -> String {
format!("{}{}",
introspect_args(&self.arguments, " ", ""),
self.anns.introspect(" "))
}
}
pub fn new_signal<D: DataType>(n: Member<'static>, data: D::Signal) -> Signal<D> {
Signal { name: n, arguments: vec!(), anns: Annotations::new(), data: data }
}
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
/// Enumerates the different signaling behaviors a Property can have
/// to being changed.
pub enum EmitsChangedSignal {
/// The Property emits a signal that includes the new value.
True,
/// The Property emits a signal that does not include the new value.
Invalidates,
/// The Property cannot be changed.
Const,
/// The Property does not emit a signal when changed.
False,
}
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
/// The possible access characteristics a Property can have.
pub enum Access {
/// The Property can only be read (Get).
Read,
/// The Property can be read or written.
ReadWrite,
/// The Property can only be written (Set).
Write,
}
impl Access {
fn introspect(&self) -> &'static str {
match self {
&Access::Read => "read",
&Access::ReadWrite => "readwrite",
&Access::Write => "write",
}
}
}
pub fn prop_append_dict<'v, M: MethodType<D> + 'v, D: DataType + 'v, I: Iterator<Item=&'v Property<M, D>>>
(iter: &mut arg::IterAppend, mut props: I, minfo: &MethodInfo<M, D>) -> Result<(), MethodErr> {
let mut result = Ok(());
iter.append_dict(&Signature::make::<&str>(), &Signature::make::<arg::Variant<bool>>(), |subiter| loop {
let p = if let Some(p) = props.next() { p } else { return };
if p.can_get().is_err() { continue; }
let pinfo = minfo.to_prop_info(minfo.iface, p);
subiter.append_dict_entry(|mut entryiter| {
entryiter.append(&*p.get_name());
result = p.get_as_variant(&mut entryiter, &pinfo);
});
if result.is_err() { return };
});
result
}
#[derive(Debug)]
/// A D-Bus Property.
pub struct Property<M: MethodType<D>, D: DataType> {
name: String,
data: D::Property,
sig: Signature<'static>,
emits: EmitsChangedSignal,
auto_emit: bool,
rw: Access,
get_cb: Option<DebugGetProp<M, D>>,
set_cb: Option<DebugSetProp<M, D>>,
anns: Annotations,
}
impl<M: MethodType<D>, D: DataType> Property<M, D> {
/// Builder method that allows setting the Property's signal
/// behavior when changed.
///
/// Note: if e is set to const, the property will be read only.
pub fn emits_changed(mut self, e: EmitsChangedSignal) -> Self {
self.emits = e;
if self.emits == EmitsChangedSignal::Const { self.rw = Access::Read };
self
}
/// Builder method that determines whether or not setting this property
/// will result in an PropertiesChanged signal. Defaults to true.
///
/// When set to true (the default), the behaviour is determined by "emits_changed".
/// When set to false, no PropertiesChanged signal will be emitted (but the signal
/// still shows up in introspection data).
/// You can still emit the signal manually by, e g, calling `add_propertieschanged`
/// and send the resulting message(s).
pub fn auto_emit_on_set(mut self, b: bool) -> Self {
self.auto_emit = b;
self
}
/// Builder method that allows setting the Property as readable,
/// writable, or both.
///
/// Note: might modify emits_changed as well, if property is changed to non-readonly and emit is set to "Const".
pub fn access(mut self, e: Access) -> Self {
self.rw = e;
if self.rw != Access::Read && self.emits == EmitsChangedSignal::Const {
self.emits = EmitsChangedSignal::False
};
self
}
/// Builder method that adds an annotation to the method.
pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
self.anns.insert(name, value); self
}
/// Builder method that adds an annotation that this entity is deprecated.
pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Get property name
pub fn get_name(&self) -> &str { &self.name }
/// Get associated data
pub fn get_data(&self) -> &D::Property { &self.data }
/// Returns Ok if the property is gettable
pub fn can_get(&self) -> Result<(), MethodErr> {
if self.rw == Access::Write || self.get_cb.is_none() {
Err(MethodErr::failed(&format!("Property {} is write only", &self.name)))
} else { Ok(()) }
}
/// Calls the on_get function and appends the result as a variant.
///
/// Note: Will panic if get_cb is not set.
pub fn get_as_variant(&self, i: &mut arg::IterAppend, pinfo: &PropInfo<M, D>) -> Result<(), MethodErr> {
let mut r = Ok(());
i.append_variant(&self.sig, |subi| {
r = M::call_getprop(&*self.get_cb.as_ref().unwrap().0, subi, pinfo);
});
r
}
/// Returns Ok if the property is settable.
///
/// Will verify signature in case iter is not None; iter is supposed to point at the Variant with the item inside.
pub fn can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr> {
use arg::Arg;
if self.rw == Access::Read || self.set_cb.is_none() || self.emits == EmitsChangedSignal::Const {
return Err(MethodErr::ro_property(&self.name))
}
if let Some(mut i) = i {
let mut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2)));
if &*subiter.signature() != &*self.sig {
return Err(MethodErr::failed(&format!("Property {} cannot change type", &self.name)))
}
}
Ok(())
}
/// Calls the on_set function, which reads from i.
///
/// The return value might contain an extra message containing the EmitsChanged signal.
/// Note: Will panic if set_cb is not set.
pub fn set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
use arg::Arg;
let mut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2)));
try!(M::call_setprop(&*self.set_cb.as_ref().unwrap().0, &mut subiter, pinfo));
self.get_emits_changed_signal(pinfo)
}
/// Gets the signal (if any) associated with the Property.
fn get_signal(&self, p: &PropInfo<M, D>) -> Message {
Message::signal(p.path.get_name(), &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
.append1(&**p.iface.get_name())
}
/// Adds this property to a list of PropertiesChanged signals.
///
/// "v" is updated with the signal for this property. "new_value" is only called if self.emits is "true",
/// it should return the value of the property.
/// If no PropertiesChanged signal should be emitted for this property, "v" is left unchanged.
pub fn add_propertieschanged<F: FnOnce() -> Box<arg::RefArg>>(&self, v: &mut Vec<PropertiesPropertiesChanged>, iface: &IfaceName, new_value: F) {
// Impl note: It is a bit silly that this function cannot be used from e g get_emits_changed_signal below,
// but it is due to the fact that we cannot create a RefArg out of an IterAppend; which is what the 'on_get'
// handler currently receives.
if self.emits == EmitsChangedSignal::Const || self.emits == EmitsChangedSignal::False { return; }
let vpos = v.iter().position(|vv| &*vv.interface_name == &**iface);
let vpos = vpos.unwrap_or_else(|| {
let mut z: PropertiesPropertiesChanged = Default::default();
z.interface_name = (&**iface).into();
v.push(z);
v.len()-1
});
let vv = &mut v[vpos];
if self.emits == EmitsChangedSignal::Invalidates {
vv.invalidated_properties.push(self.name.clone());
} else {
vv.changed_properties.insert(self.name.clone(), arg::Variant(new_value()));
}
}
fn get_emits_changed_signal(&self, m: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
if !self.auto_emit { return Ok(None) }
match self.emits {
EmitsChangedSignal::False => Ok(None),
EmitsChangedSignal::Const => Err(MethodErr::ro_property(&self.name)),
EmitsChangedSignal::True => Ok(Some({
let mut s = self.get_signal(m);
{
let mut iter = arg::IterAppend::new(&mut s);
try!(prop_append_dict(&mut iter, Some(self).into_iter(), &m.to_method_info()));
iter.append(arg::Array::<&str, _>::new(vec!()));
}
s
})),
EmitsChangedSignal::Invalidates => Ok(Some(self.get_signal(m).append2(
arg::Dict::<&str, arg::Variant<bool>, _>::new(vec!()),
arg::Array::new(Some(&*self.name).into_iter())
))),
}
}
}
impl<'a, D: DataType> Property<MTFn<D>, D> {
/// Sets the callback for getting a property.
///
/// For single-thread use.
pub fn on_get<H>(mut self, handler: H) -> Property<MTFn<D>, D>
where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
self
}
/// Sets the callback for setting a property.
///
/// For single-thread use.
pub fn on_set<H>(mut self, handler: H) -> Property<MTFn<D>, D>
where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
self
}
}
impl<'a, D: DataType> Property<MTFnMut<D>, D> {
/// Sets the callback for getting a property.
///
/// For single-thread use.
pub fn on_get<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
self.get_cb = Some(DebugGetProp(Box::new(RefCell::new(handler)) as Box<_>));
self
}
/// Sets the callback for setting a property.
///
/// For single-thread use.
pub fn on_set<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
self.set_cb = Some(DebugSetProp(Box::new(RefCell::new(handler)) as Box<_>));
self
}
}
impl<D: DataType> Property<MTSync<D>, D> {
/// Sets the callback for getting a property.
///
/// For multi-thread use.
pub fn on_get<H>(mut self, handler: H) -> Property<MTSync<D>, D>
where H: Fn(&mut arg::IterAppend, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
self
}
/// Sets the callback for setting a property.
///
/// For single-thread use.
pub fn on_set<H>(mut self, handler: H) -> Property<MTSync<D>, D>
where H: Fn(&mut arg::Iter, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
self
}
}
impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::Append + Clone {
/// Adds a "standard" get handler.
pub fn default_get(mut self) -> Self {
let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { i.append(p.prop.get_data()); Ok(()) };
self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
self
}
}
impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::RefArg {
/// Adds a "standard" get handler (for RefArgs).
pub fn default_get_refarg(mut self) -> Self {
let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { (p.prop.get_data() as &arg::RefArg).append(i); Ok(()) };
self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
self
}
}
impl<M: MethodType<D>, D: DataType> Introspect for Property<M, D> {
fn xml_name(&self) -> &'static str { "property" }
fn xml_params(&self) -> String { format!(" type=\"{}\" access=\"{}\"", self.sig, self.rw.introspect()) }
fn xml_contents(&self) -> String {
let s = match self.emits {
EmitsChangedSignal::True => return self.anns.introspect(" "),
EmitsChangedSignal::False => "false",
EmitsChangedSignal::Const => "const",
EmitsChangedSignal::Invalidates => "invalidates",
};
let mut tempanns = self.anns.clone();
tempanns.insert("org.freedesktop.DBus.Property.EmitsChangedSignal", s);
tempanns.introspect(" ")
}
}
pub fn new_property<M: MethodType<D>, D: DataType>
(n: String, sig: Signature<'static>, data: D::Property) -> Property<M, D> {
Property {
name: n, emits: EmitsChangedSignal::True, auto_emit: true, rw: Access::Read,
sig: sig, anns: Annotations::new(), set_cb: None, get_cb: None, data: data
}
}
#[test]
fn test_prop_handlers() {
use tree::Factory;
use std::collections::BTreeMap;
use arg::{Dict, Variant};
#[derive(Default, Debug)]
struct Custom;
impl DataType for Custom {
type Tree = ();
type ObjectPath = ();
type Interface = ();
type Property = i32;
type Method = ();
type Signal = ();
}
let f = Factory::new_fn::<Custom>();
let tree = f.tree(()).add(f.object_path("/test", ()).introspectable().object_manager()
.add(f.interface("com.example.test", ())
.add_p(f.property::<i32,_>("Value1", 5i32).default_get())
.add_p(f.property::<i32,_>("Value2", 9i32).default_get())
)
);
let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Get").unwrap()
.append2("com.example.test", "Value1");
::message::message_set_serial(&mut msg, 4);
let res = tree.handle(&msg).unwrap();
assert_eq!(res[0].get1(), Some(arg::Variant(5i32)));
let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Set").unwrap()
.append3("com.example.test", "Value1", arg::Variant(3i32));
::message::message_set_serial(&mut msg, 4);
let mut res = tree.handle(&msg).unwrap();
assert!(res[0].as_result().is_err());
let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "GetAll").unwrap()
.append1("com.example.test");
::message::message_set_serial(&mut msg, 4);
let res = tree.handle(&msg).unwrap();
let d: Dict<&str, Variant<i32>, _> = res[0].get1().unwrap();
let z2: BTreeMap<_, _> = d.collect();
assert_eq!(z2.get("Value1"), Some(&arg::Variant(5i32)));
assert_eq!(z2.get("Value2"), Some(&arg::Variant(9i32)));
assert_eq!(z2.get("Mooh"), None);
let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects").unwrap();
::message::message_set_serial(&mut msg, 4);
let res = tree.handle(&msg).unwrap();
let pdict: arg::Dict<Path, Dict<&str, Dict<&str, Variant<i32>, _>, _>, _> = res[0].get1().unwrap();
let pmap: BTreeMap<_, _> = pdict.collect();
let idict = pmap.get(&Path::from("/test")).unwrap();
let imap: BTreeMap<_, _> = idict.collect();
let propdict = imap.get("com.example.test").unwrap();
let propmap: BTreeMap<_, _> = propdict.collect();
assert_eq!(propmap.get("Value1"), Some(&arg::Variant(5i32)));
assert_eq!(propmap.get("Value2"), Some(&arg::Variant(9i32)));
assert_eq!(propmap.get("Mooh"), None);
}
#[test]
fn test_set_prop() {
use tree::{Factory, Access};
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::rc::Rc;
let changes = Rc::new(Cell::new(0i32));
let (changes1, changes2) = (changes.clone(), changes.clone());
let setme = Rc::new(RefCell::new("I have not been set yet!".to_owned()));
let (setme1, setme2) = (setme.clone(), setme.clone());
let f = Factory::new_fn::<()>();
let tree = f.tree(()).add(f.object_path("/example", ()).introspectable()
.add(f.interface("com.example.dbus.rs", ())
.add_p(f.property::<i32,_>("changes", ())
.on_get(move |i, _| { i.append(changes1.get()); Ok(()) }))
.add_p(f.property::<String,_>("setme", ())
.access(Access::ReadWrite)
.on_get(move |i, _| { i.append(&*setme1.borrow()); Ok(()) })
.on_set(move |i, _| {
*setme2.borrow_mut() = i.get().unwrap();
changes2.set(changes2.get() + 1);
Ok(())
}))
)
);
// Read-only
let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
.append3("com.example.dbus.rs", "changes", arg::Variant(5i32));
::message::message_set_serial(&mut msg, 20);
let mut r = tree.handle(&msg).unwrap();
assert!(r.get_mut(0).unwrap().as_result().is_err());
// Wrong type
let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
.append3("com.example.dbus.rs", "setme", arg::Variant(8i32));
::message::message_set_serial(&mut msg, 30);
let mut r = tree.handle(&msg).unwrap();
assert!(r.get_mut(0).unwrap().as_result().is_err());
// Correct!
let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
.append3("com.example.dbus.rs", "setme", arg::Variant("Correct"));
::message::message_set_serial(&mut msg, 30);
let r = tree.handle(&msg).unwrap();
assert_eq!(changes.get(), 1);
assert_eq!(&**setme.borrow(), "Correct");
println!("{:?}", r);
assert_eq!(r.len(), 2);
assert_eq!(&*r[0].member().unwrap(), "PropertiesChanged");
let (s, d): (Option<&str>, Option<arg::Dict<&str, arg::Variant<_>, _>>) = r[0].get2();
assert_eq!(s, Some("com.example.dbus.rs"));
let z2: BTreeMap<_, _> = d.unwrap().collect();
assert_eq!(z2.get("setme"), Some(&arg::Variant("Correct")));
}
#[test]
fn test_sync_prop() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tree::{Factory, Access, EmitsChangedSignal};
let f = Factory::new_sync::<()>();
let count = Arc::new(AtomicUsize::new(3));
let (cget, cset) = (count.clone(), count.clone());
let tree1 = Arc::new(f.tree(()).add(f.object_path("/syncprop", ()).introspectable()
.add(f.interface("com.example.syncprop", ())
.add_p(f.property::<u32,_>("syncprop", ())
.access(Access::ReadWrite)
.emits_changed(EmitsChangedSignal::False)
.on_get(move |i,_| { i.append(cget.load(Ordering::SeqCst) as u32); Ok(()) })
.on_set(move |i,_| { cset.store(i.get::<u32>().unwrap() as usize, Ordering::SeqCst); Ok(()) })
)
)
));
let tree2 = tree1.clone();
println!("{:#?}", tree2);
::std::thread::spawn(move || {
let mut msg = Message::new_method_call("com.example.syncprop", "/syncprop", "org.freedesktop.DBus.Properties", "Set").unwrap()
.append3("com.example.syncprop", "syncprop", arg::Variant(5u32));
::message::message_set_serial(&mut msg, 30);
let mut r = tree2.handle(&msg).unwrap();
assert!(r[0].as_result().is_ok());
});
loop {
let mut msg = Message::new_method_call("com.example.echoserver", "/syncprop", "org.freedesktop.DBus.Properties", "Get").unwrap()
.append("com.example.syncprop").append1("syncprop");
::message::message_set_serial(&mut msg, 4);
let mut r = tree1.handle(&msg).unwrap();
let r = r[0].as_result().unwrap();
let z: arg::Variant<u32> = r.get1().unwrap();
if z.0 == 5 { break; }
assert_eq!(z.0, 3);
}
assert_eq!(count.load(Ordering::SeqCst), 5);
}

View File

@ -0,0 +1,275 @@
// Methods and method types. Glue to make stuff generic over MFn, MFnMut and MSync
use std::fmt;
use {ErrorName, Message, stdintf};
use arg::{Iter, IterAppend, TypeMismatchError};
use std::marker::PhantomData;
use super::{Method, Interface, Property, ObjectPath, Tree};
use std::cell::RefCell;
use std::ffi::CString;
use super::super::Error as dbusError;
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
/// A D-Bus Method Error, containing an error name and a description.
pub struct MethodErr(ErrorName<'static>, String);
impl MethodErr {
/// Create an Invalid Args MethodErr.
pub fn invalid_arg<T: fmt::Debug>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)).into()
}
/// Create a MethodErr that there are not enough arguments given.
pub fn no_arg() -> MethodErr {
("org.freedesktop.DBus.Error.InvalidArgs", "Not enough arguments").into()
}
/// Create a MethodErr that the method failed in the way specified.
pub fn failed<T: fmt::Display>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.Failed", a.to_string()).into()
}
/// Create a MethodErr that the Interface was unknown.
pub fn no_interface<T: fmt::Display>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", a)).into()
}
/// Create a MethodErr that the Method was unknown.
pub fn no_method<T: fmt::Display>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.UnknownMethod", format!("Unknown method {}", a)).into()
}
/// Create a MethodErr that the Property was unknown.
pub fn no_property<T: fmt::Display>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", a)).into()
}
/// Create a MethodErr that the Property was read-only.
pub fn ro_property<T: fmt::Display>(a: &T) -> MethodErr {
("org.freedesktop.DBus.Error.PropertyReadOnly", format!("Property {} is read only", a)).into()
}
/// Error name accessor
pub fn errorname(&self) -> &ErrorName<'static> { &self.0 }
/// Description accessor
pub fn description(&self) -> &str { &self.1 }
/// Creates an error reply from a method call message.
///
/// Note: You normally don't need to use this function,
/// as it is called internally from Tree::handle.
pub fn to_message(&self, msg: &Message) -> Message {
msg.error(&self.0, &CString::new(&*self.1).unwrap())
}
}
impl From<TypeMismatchError> for MethodErr {
fn from(t: TypeMismatchError) -> MethodErr { ("org.freedesktop.DBus.Error.Failed", format!("{}", t)).into() }
}
impl<T: Into<ErrorName<'static>>, M: Into<String>> From<(T, M)> for MethodErr {
fn from((t, m): (T, M)) -> MethodErr { MethodErr(t.into(), m.into()) }
}
impl From<dbusError> for MethodErr {
fn from(t: dbusError) -> MethodErr {
let n = t.name().unwrap_or("org.freedesktop.DBus.Error.Failed");
let m = t.message().unwrap_or("Unknown error");
MethodErr(String::from(n).into(), m.into())
}
}
/// Result containing the Messages returned from the Method, or a MethodErr.
pub type MethodResult = Result<Vec<Message>, MethodErr>;
/// Associated data for different objects in a tree.
///
/// These currently require a debug bound, due to https://github.com/rust-lang/rust/issues/31518
pub trait DataType: Sized + Default {
/// Type of associated data on the Tree.
type Tree: fmt::Debug;
/// Type of associated data on every ObjectPath.
type ObjectPath: fmt::Debug;
/// Type of associated data on every Property.
type Property: fmt::Debug;
/// Type of associated data on every Interface.
type Interface: fmt::Debug;
/// Type of associated data on every Method.
type Method: fmt::Debug;
/// Type of associated data on every Signal.
type Signal: fmt::Debug;
}
/// No associated data for the tree.
impl DataType for () {
type Tree = ();
type ObjectPath = ();
type Interface = ();
type Property = ();
type Method = ();
type Signal = ();
}
/// A helper trait used internally to make the tree generic over MTFn, MTFnMut and MTSync.
///
/// You should not need to call these methods directly, it's primarily for internal use.
pub trait MethodType<D: DataType>: Sized + Default {
/// For internal use.
type Method: ?Sized;
/// For internal use.
type GetProp: ?Sized;
/// For internal use.
type SetProp: ?Sized;
/// For internal use.
fn call_getprop(&Self::GetProp, &mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>;
/// For internal use.
fn call_setprop(&Self::SetProp, &mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>;
/// For internal use.
fn call_method(&Self::Method, &MethodInfo<Self, D>) -> MethodResult;
/// For internal use.
fn make_getprop<H>(h: H) -> Box<Self::GetProp>
where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static;
/// For internal use.
fn make_method<H>(h: H) -> Box<Self::Method>
where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static;
}
/// An abstract type to represent Fn functions.
#[derive(Default, Debug, Copy, Clone)]
pub struct MTFn<D=()>(PhantomData<*const D>);
impl<D: DataType> MethodType<D> for MTFn<D> {
type GetProp = Fn(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>;
type SetProp = Fn(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>;
type Method = Fn(&MethodInfo<Self, D>) -> MethodResult;
fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { p(i, pinfo) }
fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { p(i, pinfo) }
fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
-> MethodResult { p(minfo) }
fn make_getprop<H>(h: H) -> Box<Self::GetProp>
where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(h) }
fn make_method<H>(h: H) -> Box<Self::Method>
where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(h) }
}
/// An abstract type to represent FnMut functions.
#[derive(Default, Debug, Copy, Clone)]
pub struct MTFnMut<D=()>(PhantomData<*const D>);
impl<D: DataType> MethodType<D> for MTFnMut<D> {
type GetProp = RefCell<FnMut(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>>;
type SetProp = RefCell<FnMut(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>>;
type Method = RefCell<FnMut(&MethodInfo<Self, D>) -> MethodResult>;
fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { (&mut *p.borrow_mut())(i, pinfo) }
fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { (&mut *p.borrow_mut())(i, pinfo) }
fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
-> MethodResult { (&mut *p.borrow_mut())(minfo) }
fn make_getprop<H>(h: H) -> Box<Self::GetProp>
where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(RefCell::new(h)) }
fn make_method<H>(h: H) -> Box<Self::Method>
where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(RefCell::new(h)) }
}
/// An abstract type to represent Fn + Send + Sync functions (that can be called from several threads in parallel).
#[derive(Default, Debug, Copy, Clone)]
pub struct MTSync<D=()>(PhantomData<*const D>);
impl<D: DataType> MethodType<D> for MTSync<D> {
type GetProp = Fn(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr> + Send + Sync + 'static;
type SetProp = Fn(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr> + Send + Sync + 'static;
type Method = Fn(&MethodInfo<Self, D>) -> MethodResult + Send + Sync + 'static;
fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { p(i, pinfo) }
fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
-> Result<(), MethodErr> { p(i, pinfo) }
fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
-> MethodResult { p(minfo) }
fn make_getprop<H>(h: H) -> Box<Self::GetProp>
where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(h) }
fn make_method<H>(h: H) -> Box<Self::Method>
where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(h) }
}
#[derive(Debug, Copy, Clone)]
/// Contains information about the incoming method call.
pub struct MethodInfo<'a, M: 'a + MethodType<D>, D: 'a + DataType> {
/// Message
pub msg: &'a Message,
/// The method to be called
pub method: &'a Method<M, D>,
/// Interface
pub iface: &'a Interface<M, D>,
/// Object path
pub path: &'a ObjectPath<M, D>,
/// Tree
pub tree: &'a Tree<M, D>,
}
impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> MethodInfo<'a, M, D> {
/// MethodInfo to PropInfo conversion
pub fn to_prop_info(&self, iface: &'a Interface<M, D>, prop: &'a Property<M, D>) -> PropInfo<'a, M, D> {
PropInfo { msg: self.msg, method: self.method, iface: iface, prop: prop, path: self.path, tree: self.tree }
}
}
impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> stdintf::OrgFreedesktopDBusIntrospectable for MethodInfo<'a, M, D> {
type Err = MethodErr;
fn introspect(&self) -> Result<String, Self::Err> { Ok(self.path.introspect(self.tree)) }
}
// Mostly autogenerated by dbus-codegen
pub fn org_freedesktop_dbus_introspectable_server<M, D>(factory: &super::Factory<M, D>, data: D::Interface) -> super::Interface<M, D>
where
D: super::DataType,
D::Method: Default,
M: MethodType<D>,
{
let i = factory.interface("org.freedesktop.DBus.Introspectable", data);
let h = move |minfo: &super::MethodInfo<M, D>| {
let d: &stdintf::OrgFreedesktopDBusIntrospectable<Err=super::MethodErr> = minfo;
let arg0 = try!(d.introspect());
let rm = minfo.msg.method_return();
let rm = rm.append1(arg0);
Ok(vec!(rm))
};
let m = factory.method_sync("Introspect", Default::default(), h);
let m = m.out_arg(("xml_data", "s"));
let i = i.add_m(m);
i
}
#[derive(Debug, Copy, Clone)]
/// Contains information about the incoming property get/set request.
pub struct PropInfo<'a, M: 'a + MethodType<D>, D: 'a + DataType> {
/// Message
pub msg: &'a Message,
/// Get, Set or GetAll
pub method: &'a Method<M, D>,
/// The property to be set/get
pub prop: &'a Property<M, D>,
/// The interface the property belongs to
pub iface: &'a Interface<M, D>,
/// Object path
pub path: &'a ObjectPath<M, D>,
/// Tree
pub tree: &'a Tree<M, D>,
}
impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> PropInfo<'a, M, D> {
/// PropInfo to MethodInfo conversion.
pub fn to_method_info(&self) -> MethodInfo<'a, M, D> {
MethodInfo { msg: self.msg, method: self.method, iface: self.iface, path: self.path, tree: self.tree }
}
}

35
third_party/rust/dbus/src/tree/mod.rs vendored Normal file
View File

@ -0,0 +1,35 @@
//! Contains functionality for dispatching methods on a D-Bus "server".
//!
//! # Example
//! ```rust,no_run
//! use dbus::{tree, Connection, BusType};
//! let f = tree::Factory::new_fn::<()>();
//! /* Add a method returning "Thanks!" on interface "com.example.dbus.rs"
//! on object path "/example". */
//! let t = f.tree(()).add(f.object_path("/example", ()).introspectable()
//! .add(f.interface("com.example.dbus.rs", ())
//! .add_m(f.method("CallMe", (), |m| {
//! Ok(vec!(m.msg.method_return().append("Thanks!"))) }
//! ).out_arg("s"))
//! ));
//!
//! let c = Connection::get_private(BusType::Session).unwrap();
//! t.set_registered(&c, true).unwrap();
//! c.add_handler(t);
//! /* Run forever */
//! loop { c.incoming(1000).next(); }
//! ```
//!
//! See `examples/server.rs` and `examples/adv_server.rs` for more thorough examples.
mod utils;
mod methodtype;
mod leaves;
mod objectpath;
mod factory;
pub use self::utils::{Argument, Iter};
pub use self::methodtype::{MethodErr, MethodInfo, PropInfo, MethodResult, MethodType, DataType, MTFn, MTFnMut, MTSync};
pub use self::leaves::{Method, Signal, Property, Access, EmitsChangedSignal};
pub use self::objectpath::{Interface, ObjectPath, Tree, TreeServer};
pub use self::factory::Factory;

View File

@ -0,0 +1,536 @@
use super::utils::{ArcMap, Iter, IterE, Annotations, Introspect};
use super::{Factory, MethodType, MethodInfo, MethodResult, MethodErr, DataType, Property, Method, Signal, methodtype};
use std::sync::{Arc, Mutex};
use {Member, Message, Path, Signature, MessageType, Connection, ConnectionItem, Error, arg, MsgHandler, MsgHandlerType, MsgHandlerResult};
use Interface as IfaceName;
use std::fmt;
use std::ffi::CStr;
use super::leaves::prop_append_dict;
fn introspect_map<I: fmt::Display, T: Introspect>
(h: &ArcMap<I, T>, indent: &str) -> String {
h.iter().fold("".into(), |a, (k, v)| {
let (name, params, contents) = (v.xml_name(), v.xml_params(), v.xml_contents());
format!("{}{}<{} name=\"{}\"{}{}>\n",
a, indent, name, &*k, params, if contents.len() > 0 {
format!(">\n{}{}</{}", contents, indent, name)
}
else { format!("/") }
)
})
}
#[derive(Debug)]
/// Represents a D-Bus interface.
pub struct Interface<M: MethodType<D>, D: DataType> {
name: Arc<IfaceName<'static>>,
methods: ArcMap<Member<'static>, Method<M, D>>,
signals: ArcMap<Member<'static>, Signal<D>>,
properties: ArcMap<String, Property<M, D>>,
anns: Annotations,
data: D::Interface,
}
impl<M: MethodType<D>, D: DataType> Interface<M, D> {
/// Builder function that adds a method to the interface.
pub fn add_m<I: Into<Arc<Method<M, D>>>>(mut self, m: I) -> Self {
let m = m.into();
self.methods.insert(m.get_name().clone(), m);
self
}
/// Builder function that adds a signal to the interface.
pub fn add_s<I: Into<Arc<Signal<D>>>>(mut self, s: I) -> Self {
let m = s.into();
self.signals.insert(m.get_name().clone(), m);
self
}
/// Builder function that adds a property to the interface.
pub fn add_p<I: Into<Arc<Property<M, D>>>>(mut self, p: I) -> Self {
let m = p.into();
self.properties.insert(m.get_name().to_owned(), m);
self
}
/// Builder function that adds an annotation to this interface.
pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
self.anns.insert(name, value); self
}
/// Builder function that adds an annotation that this entity is deprecated.
pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Get interface name
pub fn get_name(&self) -> &IfaceName<'static> { &self.name }
/// Get associated data
pub fn get_data(&self) -> &D::Interface { &self.data }
/// Iterates over methods implemented by this interface.
pub fn iter_m<'a>(&'a self) -> Iter<'a, Method<M, D>> { IterE::Member(self.methods.values()).into() }
/// Iterates over signals implemented by this interface.
pub fn iter_s<'a>(&'a self) -> Iter<'a, Signal<D>> { IterE::Member(self.signals.values()).into() }
/// Iterates over properties implemented by this interface.
pub fn iter_p<'a>(&'a self) -> Iter<'a, Property<M, D>> { IterE::String(self.properties.values()).into() }
}
impl<M: MethodType<D>, D: DataType> Introspect for Interface<M, D> {
fn xml_name(&self) -> &'static str { "interface" }
fn xml_params(&self) -> String { String::new() }
fn xml_contents(&self) -> String {
format!("{}{}{}{}",
introspect_map(&self.methods, " "),
introspect_map(&self.properties, " "),
introspect_map(&self.signals, " "),
self.anns.introspect(" "))
}
}
pub fn new_interface<M: MethodType<D>, D: DataType>(t: IfaceName<'static>, d: D::Interface) -> Interface<M, D> {
Interface { name: Arc::new(t), methods: ArcMap::new(), signals: ArcMap::new(),
properties: ArcMap::new(), anns: Annotations::new(), data: d
}
}
#[derive(Debug)]
/// Cache of built-in interfaces, in order to save memory when many object paths implement the same interface(s).
pub struct IfaceCache<M: MethodType<D>, D: DataType>(Mutex<ArcMap<IfaceName<'static>, Interface<M, D>>>);
impl<M: MethodType<D>, D: DataType> IfaceCache<M, D>
where D::Interface: Default {
pub fn get<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>>
where F: FnOnce(Interface<M, D>) -> Interface<M, D> {
let s2 = s.clone().into();
let mut m = self.0.lock().unwrap();
m.entry(s2).or_insert_with(|| {
let i = new_interface(s.into(), Default::default());
Arc::new(f(i))
}).clone()
}
}
impl<M: MethodType<D>, D: DataType> IfaceCache<M, D> {
pub fn get_factory<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>>
where F: FnOnce() -> Interface<M, D> {
let s2 = s.clone().into();
let mut m = self.0.lock().unwrap();
m.entry(s2).or_insert_with(|| {
Arc::new(f())
}).clone()
}
pub fn new() -> Arc<Self> { Arc::new(IfaceCache(Mutex::new(ArcMap::new()))) }
}
#[derive(Debug)]
/// A D-Bus Object Path.
pub struct ObjectPath<M: MethodType<D>, D: DataType> {
name: Arc<Path<'static>>,
ifaces: ArcMap<Arc<IfaceName<'static>>, Interface<M, D>>,
ifacecache: Arc<IfaceCache<M, D>>,
data: D::ObjectPath,
}
impl<M: MethodType<D>, D: DataType> ObjectPath<M, D> {
/// Get property name
pub fn get_name(&self) -> &Path<'static> { &self.name }
/// Get associated data
pub fn get_data(&self) -> &D::ObjectPath { &self.data }
/// Iterates over interfaces implemented by this object path.
pub fn iter<'a>(&'a self) -> Iter<'a, Interface<M, D>> { IterE::Iface(self.ifaces.values()).into() }
pub(super) fn introspect(&self, tree: &Tree<M, D>) -> String {
let ifacestr = introspect_map(&self.ifaces, " ");
let olen = self.name.len()+1;
let childstr = tree.children(self, true).iter().fold("".to_string(), |na, n|
format!("{} <node name=\"{}\"/>\n", na, &n.name[olen..])
);
let nodestr = format!(r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="{}">
{}{}</node>"##, self.name, ifacestr, childstr);
nodestr
}
fn get_iface<'a>(&'a self, iface_name: &'a CStr) -> Result<&Arc<Interface<M, D>>, MethodErr> {
let j = try!(IfaceName::from_slice(iface_name.to_bytes_with_nul()).map_err(|e| MethodErr::invalid_arg(&e)));
self.ifaces.get(&j).ok_or_else(|| MethodErr::no_interface(&j))
}
fn prop_get(&self, m: &MethodInfo<M, D>) -> MethodResult {
let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
let iface = try!(self.get_iface(iname));
let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
.ok_or_else(|| MethodErr::no_property(&prop_name)));
try!(prop.can_get());
let mut mret = m.msg.method_return();
{
let mut iter = arg::IterAppend::new(&mut mret);
let pinfo = m.to_prop_info(iface, prop);
try!(prop.get_as_variant(&mut iter, &pinfo));
}
Ok(vec!(mret))
}
fn prop_get_all(&self, m: &MethodInfo<M, D>) -> MethodResult {
let iface = try!(self.get_iface(try!(m.msg.read1())));
let mut mret = m.msg.method_return();
try!(prop_append_dict(&mut arg::IterAppend::new(&mut mret),
iface.properties.values().map(|v| &**v), m));
Ok(vec!(mret))
}
fn prop_set(&self, m: &MethodInfo<M, D>) -> MethodResult {
let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
let iface = try!(self.get_iface(iname));
let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
.ok_or_else(|| MethodErr::no_property(&prop_name)));
let mut iter = arg::Iter::new(m.msg);
iter.next(); iter.next();
let mut iter2 = iter;
try!(prop.can_set(Some(iter)));
let pinfo = m.to_prop_info(iface, prop);
let mut r: Vec<Message> = try!(prop.set_as_variant(&mut iter2, &pinfo)).into_iter().collect();
r.push(m.msg.method_return());
Ok(r)
}
fn get_managed_objects(&self, m: &MethodInfo<M, D>) -> MethodResult {
use arg::{Dict, Variant};
let mut paths = m.tree.children(&self, false);
paths.push(&self);
let mut result = Ok(());
let mut r = m.msg.method_return();
{
let mut i = arg::IterAppend::new(&mut r);
i.append_dict(&Signature::make::<Path>(), &Signature::make::<Dict<&str,Dict<&str,Variant<()>,()>,()>>(), |ii| {
for p in paths {
ii.append_dict_entry(|pi| {
pi.append(&*p.name);
pi.append_dict(&Signature::make::<&str>(), &Signature::make::<Dict<&str,Variant<()>,()>>(), |pii| {
for ifaces in p.ifaces.values() {
let m2 = MethodInfo { msg: m.msg, path: p, iface: ifaces, tree: m.tree, method: m.method };
pii.append_dict_entry(|ppii| {
ppii.append(&**ifaces.name);
result = prop_append_dict(ppii, ifaces.properties.values().map(|v| &**v), &m2);
});
if result.is_err() { break; }
}
});
});
if result.is_err() { break; }
}
});
}
try!(result);
Ok(vec!(r))
}
fn handle(&self, m: &Message, t: &Tree<M, D>) -> MethodResult {
let i = try!(m.interface().and_then(|i| self.ifaces.get(&i)).ok_or_else(|| MethodErr::no_interface(&"")));
let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or_else(|| MethodErr::no_method(&"")));
let minfo = MethodInfo { msg: m, tree: t, path: self, iface: i, method: me };
me.call(&minfo)
}
}
impl<M: MethodType<D>, D: DataType> ObjectPath<M, D>
where <D as DataType>::Interface: Default, <D as DataType>::Method: Default
{
/// Adds introspection support for this object path.
pub fn introspectable(self) -> Self {
let z = self.ifacecache.get_factory("org.freedesktop.DBus.Introspectable", || {
let f = Factory::from(self.ifacecache.clone());
methodtype::org_freedesktop_dbus_introspectable_server(&f, Default::default())
});
self.add(z)
}
/// Builder function that adds a interface to the object path.
pub fn add<I: Into<Arc<Interface<M, D>>>>(mut self, s: I) -> Self {
let m = s.into();
if !m.properties.is_empty() { self.add_property_handler(); }
self.ifaces.insert(m.name.clone(), m);
self
}
/// Adds ObjectManager support for this object path.
///
/// It is not possible to add/remove interfaces while the object path belongs to a tree,
/// hence no InterfacesAdded / InterfacesRemoved signals are sent.
pub fn object_manager(mut self) -> Self {
use arg::{Variant, Dict};
let ifname = IfaceName::from("org.freedesktop.DBus.ObjectManager");
if self.ifaces.contains_key(&ifname) { return self };
let z = self.ifacecache.get(ifname, |i| {
i.add_m(super::leaves::new_method("GetManagedObjects".into(), Default::default(),
M::make_method(|m| m.path.get_managed_objects(m)))
.outarg::<Dict<Path,Dict<&str,Dict<&str,Variant<()>,()>,()>,()>,_>("objpath_interfaces_and_properties"))
});
self.ifaces.insert(z.name.clone(), z);
self
}
fn add_property_handler(&mut self) {
use arg::{Variant, Dict};
let ifname = IfaceName::from("org.freedesktop.DBus.Properties");
if self.ifaces.contains_key(&ifname) { return };
let z = self.ifacecache.get(ifname, |i| {
i.add_m(super::leaves::new_method("Get".into(), Default::default(),
M::make_method(|m| m.path.prop_get(m)))
.inarg::<&str,_>("interface_name")
.inarg::<&str,_>("property_name")
.outarg::<Variant<()>,_>("value"))
.add_m(super::leaves::new_method("GetAll".into(), Default::default(),
M::make_method(|m| m.path.prop_get_all(m)))
.inarg::<&str,_>("interface_name")
.outarg::<Dict<&str, Variant<()>, ()>,_>("props"))
.add_m(super::leaves::new_method("Set".into(), Default::default(),
M::make_method(|m| m.path.prop_set(m)))
.inarg::<&str,_>("interface_name")
.inarg::<&str,_>("property_name")
.inarg::<Variant<bool>,_>("value"))
});
self.ifaces.insert(z.name.clone(), z);
}
}
pub fn new_objectpath<M: MethodType<D>, D: DataType>(n: Path<'static>, d: D::ObjectPath, cache: Arc<IfaceCache<M, D>>)
-> ObjectPath<M, D> {
ObjectPath { name: Arc::new(n), data: d, ifaces: ArcMap::new(), ifacecache: cache }
}
/// A collection of object paths.
#[derive(Debug, Default)]
pub struct Tree<M: MethodType<D>, D: DataType> {
paths: ArcMap<Arc<Path<'static>>, ObjectPath<M, D>>,
data: D::Tree,
}
impl<M: MethodType<D>, D: DataType> Tree<M, D> {
/// Builder function that adds an object path to this tree.
///
/// Note: This does not register a path with the connection, so if the tree is currently registered,
/// you might want to call Connection::register_object_path to add the path manually.
pub fn add<I: Into<Arc<ObjectPath<M, D>>>>(mut self, s: I) -> Self {
self.insert(s);
self
}
/// Get a reference to an object path from the tree.
pub fn get(&self, p: &Path<'static>) -> Option<&Arc<ObjectPath<M, D>>> {
self.paths.get(p)
}
/// Iterates over object paths in this tree.
pub fn iter<'a>(&'a self) -> Iter<'a, ObjectPath<M, D>> { IterE::Path(self.paths.values()).into() }
/// Non-builder function that adds an object path to this tree.
///
/// Note: This does not register a path with the connection, so if the tree is currently registered,
/// you might want to call Connection::register_object_path to add the path manually.
pub fn insert<I: Into<Arc<ObjectPath<M, D>>>>(&mut self, s: I) {
let m = s.into();
self.paths.insert(m.name.clone(), m);
}
/// Remove a object path from the Tree. Returns the object path removed, or None if not found.
///
/// Note: This does not unregister a path with the connection, so if the tree is currently registered,
/// you might want to call Connection::unregister_object_path to remove the path manually.
pub fn remove(&mut self, p: &Path<'static>) -> Option<Arc<ObjectPath<M, D>>> {
// There is no real reason p needs to have a static lifetime; but
// the borrow checker doesn't agree. :-(
self.paths.remove(p)
}
/// Registers or unregisters all object paths in the tree.
pub fn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> {
let mut regd_paths = Vec::new();
for p in self.paths.keys() {
if b {
match c.register_object_path(p) {
Ok(()) => regd_paths.push(p.clone()),
Err(e) => {
while let Some(rp) = regd_paths.pop() {
c.unregister_object_path(&rp);
}
return Err(e)
}
}
} else {
c.unregister_object_path(p);
}
}
Ok(())
}
/// This method takes an `ConnectionItem` iterator (you get it from `Connection::iter()`)
/// and handles all matching items. Non-matching items (e g signals) are passed through.
pub fn run<'a, I: Iterator<Item=ConnectionItem>>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M, D> {
TreeServer { iter: i, tree: &self, conn: c }
}
/// Handles a message.
///
/// Will return None in case the object path was not
/// found in this tree, or otherwise a list of messages to be sent back.
pub fn handle(&self, m: &Message) -> Option<Vec<Message>> {
if m.msg_type() != MessageType::MethodCall { None }
else { m.path().and_then(|p| self.paths.get(&p).map(|s| s.handle(m, &self)
.unwrap_or_else(|e| vec!(e.to_message(m))))) }
}
fn children(&self, o: &ObjectPath<M, D>, direct_only: bool) -> Vec<&ObjectPath<M, D>> {
let parent: &str = &o.name;
let plen = parent.len()+1;
self.paths.values().filter_map(|v| {
let k: &str = &v.name;
if !k.starts_with(parent) || k.len() <= plen || &k[plen-1..plen] != "/" {None} else {
let child = &k[plen..];
if direct_only && child.contains("/") {None} else {Some(&**v)}
}
}).collect()
}
/// Get associated data
pub fn get_data(&self) -> &D::Tree { &self.data }
}
pub fn new_tree<M: MethodType<D>, D: DataType>(d: D::Tree) -> Tree<M, D> {
Tree { paths: ArcMap::new(), data: d }
}
impl<M: MethodType<D>, D: DataType> MsgHandler for Tree<M, D> {
fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
}
fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
}
impl<M: MethodType<D>, D: DataType> MsgHandler for Arc<Tree<M, D>> {
fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
}
fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
}
/// An iterator adapter that handles incoming method calls.
///
/// Method calls that match an object path in the tree are handled and consumed by this
/// iterator. Other messages are passed through.
pub struct TreeServer<'a, I, M: MethodType<D> + 'a, D: DataType + 'a> {
iter: I,
conn: &'a Connection,
tree: &'a Tree<M, D>,
}
impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType<D>, D: DataType + 'a> Iterator for TreeServer<'a, I, M, D> {
type Item = ConnectionItem;
fn next(&mut self) -> Option<ConnectionItem> {
loop {
let n = self.iter.next();
if let &Some(ConnectionItem::MethodCall(ref msg)) = &n {
if let Some(v) = self.tree.handle(&msg) {
// Probably the wisest is to ignore any send errors here -
// maybe the remote has disconnected during our processing.
for m in v { let _ = self.conn.send(m); };
continue;
}
}
return n;
}
}
}
#[test]
fn test_iter() {
let f = super::Factory::new_fn::<()>();
let t = f.tree(())
.add(f.object_path("/echo", ()).introspectable()
.add(f.interface("com.example.echo", ())
.add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
.add_p(f.property::<i32,_>("EchoCount", ()))
.add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated()
)
)).add(f.object_path("/echo/subpath", ()));
let paths: Vec<_> = t.iter().collect();
assert_eq!(paths.len(), 2);
}
#[test]
fn test_introspection() {
let f = super::Factory::new_fn::<()>();
let t = f.object_path("/echo", ()).introspectable()
.add(f.interface("com.example.echo", ())
.add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
.add_p(f.property::<i32,_>("EchoCount", ()))
.add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated())
);
let actual_result = t.introspect(&f.tree(()).add(f.object_path("/echo/subpath", ())));
println!("\n=== Introspection XML start ===\n{}\n=== Introspection XML end ===", actual_result);
let expected_result = r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/echo">
<interface name="com.example.echo">
<method name="Echo">
<arg name="request" type="s" direction="in"/>
<arg name="reply" type="s" direction="out"/>
</method>
<property name="EchoCount" type="i" access="read"/>
<signal name="Echoed">
<arg name="data" type="s"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="xml_data" type="s" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface_name" type="s" direction="in"/>
<arg name="property_name" type="s" direction="in"/>
<arg name="value" type="v" direction="out"/>
</method>
<method name="GetAll">
<arg name="interface_name" type="s" direction="in"/>
<arg name="props" type="a{sv}" direction="out"/>
</method>
<method name="Set">
<arg name="interface_name" type="s" direction="in"/>
<arg name="property_name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
</interface>
<node name="subpath"/>
</node>"##;
assert_eq!(expected_result, actual_result);
}

100
third_party/rust/dbus/src/tree/utils.rs vendored Normal file
View File

@ -0,0 +1,100 @@
// Small structs that don't have their own unit.
use {Signature, Member, Path, Interface as IfaceName};
use std::collections::{BTreeMap, btree_map};
use std::sync::Arc;
pub type ArcMap<K, V> = BTreeMap<K, Arc<V>>;
#[derive(Clone, Debug)]
pub enum IterE<'a, V: 'a> {
Path(btree_map::Values<'a, Arc<Path<'static>>, Arc<V>>),
Iface(btree_map::Values<'a, Arc<IfaceName<'static>>, Arc<V>>),
Member(btree_map::Values<'a, Member<'static>, Arc<V>>),
String(btree_map::Values<'a, String, Arc<V>>),
}
#[derive(Clone, Debug)]
/// Iterator struct, returned from iterator methods on Tree, Objectpath and Interface.
pub struct Iter<'a, V: 'a>(IterE<'a, V>);
impl<'a, V: 'a> From<IterE<'a, V>> for Iter<'a, V> { fn from(x: IterE<'a, V>) -> Iter<'a, V> { Iter(x) }}
impl<'a, V: 'a> Iterator for Iter<'a, V> {
type Item = &'a Arc<V>;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
IterE::Path(ref mut x) => x.next(),
IterE::Iface(ref mut x) => x.next(),
IterE::Member(ref mut x) => x.next(),
IterE::String(ref mut x) => x.next(),
}
}
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
/// A D-Bus Argument.
pub struct Argument(Option<String>, Signature<'static>);
impl Argument {
/// Create a new Argument.
pub fn new(name: Option<String>, sig: Signature<'static>) -> Argument { Argument(name, sig) }
/// Descriptive name (if any).
pub fn name(&self) -> Option<&str> { self.0.as_ref().map(|s| &**s) }
/// Type signature of argument.
pub fn signature(&self) -> &Signature<'static> { &self.1 }
fn introspect(&self, indent: &str, dir: &str) -> String {
let n = self.0.as_ref().map(|n| format!("name=\"{}\" ", n)).unwrap_or("".into());
format!("{}<arg {}type=\"{}\"{}/>\n", indent, n, self.1, dir)
}
}
pub fn introspect_args(args: &[Argument], indent: &str, dir: &str) -> String {
args.iter().fold("".to_string(), |aa, az| format!("{}{}", aa, az.introspect(indent, dir)))
}
// Small helper struct to reduce memory somewhat for objects without annotations
#[derive(Clone, Debug, Default)]
pub struct Annotations(Option<BTreeMap<String, String>>);
impl Annotations {
pub fn new() -> Annotations { Annotations(None) }
pub fn insert<N: Into<String>, V: Into<String>>(&mut self, n: N, v: V) {
if self.0.is_none() { self.0 = Some(BTreeMap::new()) }
self.0.as_mut().unwrap().insert(n.into(), v.into());
}
pub fn introspect(&self, indent: &str) -> String {
self.0.as_ref().map(|s| s.iter().fold("".into(), |aa, (ak, av)| {
format!("{}{}<annotation name=\"{}\" value=\"{}\"/>\n", aa, indent, ak, av)
})).unwrap_or(String::new())
}
}
// Doesn't work, conflicting impls
// impl<S: Into<Signature>> From<S> for Argument
impl From<Signature<'static>> for Argument {
fn from(t: Signature<'static>) -> Argument { Argument(None, t) }
}
impl<'a> From<&'a str> for Argument {
fn from(t: &'a str) -> Argument { Argument(None, String::from(t).into()) }
}
impl<N: Into<String>, S: Into<Signature<'static>>> From<(N, S)> for Argument {
fn from((n, s): (N, S)) -> Argument { Argument(Some(n.into()), s.into()) }
}
pub trait Introspect {
// At some point we might want to switch to fmt::Write / fmt::Formatter for performance...
fn xml_name(&self) -> &'static str;
fn xml_params(&self) -> String;
fn xml_contents(&self) -> String;
}

242
third_party/rust/dbus/src/watch.rs vendored Normal file
View File

@ -0,0 +1,242 @@
use ffi;
use libc;
use super::Connection;
use std::mem;
use std::sync::{Mutex, RwLock};
use std::os::unix::io::{RawFd, AsRawFd};
use std::os::raw::{c_void, c_uint};
/// A file descriptor to watch for incoming events (for async I/O).
///
/// # Example
/// ```
/// extern crate libc;
/// extern crate dbus;
/// fn main() {
/// use dbus::{Connection, BusType, WatchEvent};
/// let c = Connection::get_private(BusType::Session).unwrap();
///
/// // Get a list of fds to poll for
/// let mut fds: Vec<_> = c.watch_fds().iter().map(|w| w.to_pollfd()).collect();
///
/// // Poll them with a 1 s timeout
/// let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, 1000) };
/// assert!(r >= 0);
///
/// // And handle incoming events
/// for pfd in fds.iter().filter(|pfd| pfd.revents != 0) {
/// for item in c.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
/// // Handle item
/// println!("Received ConnectionItem: {:?}", item);
/// }
/// }
/// }
/// ```
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
/// The enum is here for backwards compatibility mostly.
///
/// It should really be bitflags instead.
pub enum WatchEvent {
/// The fd is readable
Readable = ffi::DBUS_WATCH_READABLE as isize,
/// The fd is writable
Writable = ffi::DBUS_WATCH_WRITABLE as isize,
/// An error occured on the fd
Error = ffi::DBUS_WATCH_ERROR as isize,
/// The fd received a hangup.
Hangup = ffi::DBUS_WATCH_HANGUP as isize,
}
impl WatchEvent {
/// After running poll, this transforms the revents into a parameter you can send into `Connection::watch_handle`
pub fn from_revents(revents: libc::c_short) -> c_uint {
0 +
if (revents & libc::POLLIN) != 0 { WatchEvent::Readable as c_uint } else { 0 } +
if (revents & libc::POLLOUT) != 0 { WatchEvent::Writable as c_uint } else { 0 } +
if (revents & libc::POLLERR) != 0 { WatchEvent::Error as c_uint } else { 0 } +
if (revents & libc::POLLHUP) != 0 { WatchEvent::Hangup as c_uint } else { 0 }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A file descriptor, and an indication whether it should be read from, written to, or both.
pub struct Watch {
fd: RawFd,
read: bool,
write: bool,
}
impl Watch {
/// Get the RawFd this Watch is for
pub fn fd(&self) -> RawFd { self.fd }
/// Add POLLIN to events to listen for
pub fn readable(&self) -> bool { self.read }
/// Add POLLOUT to events to listen for
pub fn writable(&self) -> bool { self.write }
/// Returns the current watch as a libc::pollfd, to use with libc::poll
pub fn to_pollfd(&self) -> libc::pollfd {
libc::pollfd { fd: self.fd, revents: 0, events: libc::POLLERR + libc::POLLHUP +
if self.readable() { libc::POLLIN } else { 0 } +
if self.writable() { libc::POLLOUT } else { 0 },
}
}
}
impl AsRawFd for Watch {
fn as_raw_fd(&self) -> RawFd { self.fd }
}
/// Note - internal struct, not to be used outside API. Moving it outside its box will break things.
pub struct WatchList {
watches: RwLock<Vec<*mut ffi::DBusWatch>>,
enabled_fds: Mutex<Vec<Watch>>,
on_update: Mutex<Box<Fn(Watch) + Send>>,
}
impl WatchList {
pub fn new(c: &Connection, on_update: Box<Fn(Watch) + Send>) -> Box<WatchList> {
let w = Box::new(WatchList { on_update: Mutex::new(on_update), watches: RwLock::new(vec!()), enabled_fds: Mutex::new(vec!()) });
if unsafe { ffi::dbus_connection_set_watch_functions(super::connection::conn_handle(c),
Some(add_watch_cb), Some(remove_watch_cb), Some(toggled_watch_cb), &*w as *const _ as *mut _, None) } == 0 {
panic!("dbus_connection_set_watch_functions failed");
}
w
}
pub fn set_on_update(&self, on_update: Box<Fn(Watch) + Send>) { *self.on_update.lock().unwrap() = on_update; }
pub fn watch_handle(&self, fd: RawFd, flags: c_uint) {
// println!("watch_handle {} flags {}", fd, flags);
for &q in self.watches.read().unwrap().iter() {
let w = self.get_watch(q);
if w.fd != fd { continue };
if unsafe { ffi::dbus_watch_handle(q, flags) } == 0 {
panic!("dbus_watch_handle failed");
}
self.update(q);
};
}
pub fn get_enabled_fds(&self) -> Vec<Watch> {
self.enabled_fds.lock().unwrap().clone()
}
fn get_watch(&self, watch: *mut ffi::DBusWatch) -> Watch {
let mut w = Watch { fd: unsafe { ffi::dbus_watch_get_unix_fd(watch) }, read: false, write: false};
let enabled = self.watches.read().unwrap().contains(&watch) && unsafe { ffi::dbus_watch_get_enabled(watch) != 0 };
let flags = unsafe { ffi::dbus_watch_get_flags(watch) };
if enabled {
w.read = (flags & WatchEvent::Readable as c_uint) != 0;
w.write = (flags & WatchEvent::Writable as c_uint) != 0;
}
// println!("Get watch fd {:?} ptr {:?} enabled {:?} flags {:?}", w, watch, enabled, flags);
w
}
fn update(&self, watch: *mut ffi::DBusWatch) {
let mut w = self.get_watch(watch);
for &q in self.watches.read().unwrap().iter() {
if q == watch { continue };
let ww = self.get_watch(q);
if ww.fd != w.fd { continue };
w.read |= ww.read;
w.write |= ww.write;
}
// println!("Updated sum: {:?}", w);
{
let mut fdarr = self.enabled_fds.lock().unwrap();
if w.write || w.read {
if fdarr.contains(&w) { return; } // Nothing changed
}
else if !fdarr.iter().any(|q| w.fd == q.fd) { return; } // Nothing changed
fdarr.retain(|f| f.fd != w.fd);
if w.write || w.read { fdarr.push(w) };
}
let func = self.on_update.lock().unwrap();
(*func)(w);
}
}
extern "C" fn add_watch_cb(watch: *mut ffi::DBusWatch, data: *mut c_void) -> u32 {
let wlist: &WatchList = unsafe { mem::transmute(data) };
// println!("Add watch {:?}", watch);
wlist.watches.write().unwrap().push(watch);
wlist.update(watch);
1
}
extern "C" fn remove_watch_cb(watch: *mut ffi::DBusWatch, data: *mut c_void) {
let wlist: &WatchList = unsafe { mem::transmute(data) };
// println!("Removed watch {:?}", watch);
wlist.watches.write().unwrap().retain(|w| *w != watch);
wlist.update(watch);
}
extern "C" fn toggled_watch_cb(watch: *mut ffi::DBusWatch, data: *mut c_void) {
let wlist: &WatchList = unsafe { mem::transmute(data) };
// println!("Toggled watch {:?}", watch);
wlist.update(watch);
}
#[cfg(test)]
mod test {
use libc;
use super::super::{Connection, Message, BusType, WatchEvent, ConnectionItem, MessageType};
#[test]
fn async() {
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/test").unwrap();
let m = Message::new_method_call(&c.unique_name(), "/test", "com.example.asynctest", "AsyncTest").unwrap();
let serial = c.send(m).unwrap();
println!("Async: sent serial {}", serial);
let mut fds: Vec<_> = c.watch_fds().iter().map(|w| w.to_pollfd()).collect();
let mut new_fds = None;
let mut i = 0;
let mut success = false;
while !success {
i += 1;
if let Some(q) = new_fds { fds = q; new_fds = None };
for f in fds.iter_mut() { f.revents = 0 };
assert!(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, 1000) } > 0);
for f in fds.iter().filter(|pfd| pfd.revents != 0) {
let m = WatchEvent::from_revents(f.revents);
println!("Async: fd {}, revents {} -> {}", f.fd, f.revents, m);
assert!(f.revents & libc::POLLIN != 0 || f.revents & libc::POLLOUT != 0);
for e in c.watch_handle(f.fd, m) {
println!("Async: got {:?}", e);
match e {
ConnectionItem::MethodCall(m) => {
assert_eq!(m.headers(), (MessageType::MethodCall, Some("/test".to_string()),
Some("com.example.asynctest".into()), Some("AsyncTest".to_string())));
let mut mr = Message::new_method_return(&m).unwrap();
mr.append_items(&["Goodies".into()]);
c.send(mr).unwrap();
}
ConnectionItem::MethodReturn(m) => {
assert_eq!(m.headers().0, MessageType::MethodReturn);
assert_eq!(m.get_reply_serial().unwrap(), serial);
let i = m.get_items();
let s: &str = i[0].inner().unwrap();
assert_eq!(s, "Goodies");
success = true;
}
_ => (),
}
}
if i > 100 { panic!() };
}
}
}
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"7054b852a13a318562f3ef791e69802f234c9f3d943f2de2d1cef8b31fd0939a","LICENSE-APACHE":"453745410e3be8cf25d56872ea2aec975a78e6c9f217443d0bf908a5bce7c8ff","LICENSE-MIT":"de3911c2d98c8bd2d701ee721347053d9b55995a11f9a8c955e44d3ca1b376bf","build.rs":"9fbc218277d76a570c01c5795a7c8008f5458317cc036d7c88b1dc1a4af22fb7","src/lib.rs":"c8a0d43a3b7e9c8828d4946437379f1985492bd6b04fdd5e967bbcace2197c3d"},"package":"18cb88963258d00f4962205dbb5933d82780d9962c8c8a064b651d2ad7189210"}

28
third_party/rust/libdbus-sys/Cargo.toml vendored Normal file
View File

@ -0,0 +1,28 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "libdbus-sys"
version = "0.1.5"
authors = ["David Henningsson <diwic@ubuntu.com>"]
build = "build.rs"
links = "dbus"
description = "FFI bindings to libdbus."
documentation = "http://docs.rs/libdbus-sys"
keywords = ["D-Bus", "DBus", "libdbus"]
categories = ["os::unix-apis", "external-ffi-bindings"]
license = "Apache-2.0/MIT"
repository = "https://github.com/diwic/dbus-rs"
[package.metadata.pkg-config]
dbus-1 = "1.6"
[build-dependencies.pkg-config]
version = "0.3"

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014-2018 David Henningsson <diwic@ubuntu.com> and other contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,19 @@
Copyright (c) 2014-2018 David Henningsson <diwic@ubuntu.com> and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
third_party/rust/libdbus-sys/build.rs vendored Normal file
View File

@ -0,0 +1,7 @@
extern crate pkg_config;
fn main() {
// See https://github.com/joshtriplett/metadeps/issues/9 for why we don't use
// metadeps here, but instead keep this manually in sync with Cargo.toml.
pkg_config::Config::new().atleast_version("1.6").probe("dbus-1").unwrap();
}

300
third_party/rust/libdbus-sys/src/lib.rs vendored Normal file
View File

@ -0,0 +1,300 @@
use std::os::raw::{c_void, c_char, c_uint, c_int, c_long};
pub type DBusConnection = c_void;
pub type DBusMessage = c_void;
pub type DBusWatch = c_void;
pub type DBusPendingCall = c_void;
pub type DBusTimeout = c_void;
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusBusType {
Session = 0,
System = 1,
Starter = 2,
}
pub const DBUS_TYPE_ARRAY: c_int = 'a' as c_int;
pub const DBUS_TYPE_VARIANT: c_int = 'v' as c_int;
pub const DBUS_TYPE_BOOLEAN: c_int = 'b' as c_int;
pub const DBUS_TYPE_INVALID: c_int = 0;
pub const DBUS_TYPE_STRING: c_int = 's' as c_int;
pub const DBUS_TYPE_DICT_ENTRY: c_int = 'e' as c_int;
pub const DBUS_TYPE_BYTE: c_int = 'y' as c_int;
pub const DBUS_TYPE_INT16: c_int = 'n' as c_int;
pub const DBUS_TYPE_UINT16: c_int = 'q' as c_int;
pub const DBUS_TYPE_INT32: c_int = 'i' as c_int;
pub const DBUS_TYPE_UINT32: c_int = 'u' as c_int;
pub const DBUS_TYPE_INT64: c_int = 'x' as c_int;
pub const DBUS_TYPE_UINT64: c_int = 't' as c_int;
pub const DBUS_TYPE_DOUBLE: c_int = 'd' as c_int;
pub const DBUS_TYPE_UNIX_FD: c_int = 'h' as c_int;
pub const DBUS_TYPE_STRUCT: c_int = 'r' as c_int;
pub const DBUS_TYPE_OBJECT_PATH: c_int = 'o' as c_int;
pub const DBUS_TYPE_SIGNATURE: c_int = 'g' as c_int;
pub const DBUS_TIMEOUT_USE_DEFAULT: c_int = -1;
pub const DBUS_TIMEOUT_INFINITE: c_int = 0x7fffffff;
pub const DBUS_NAME_FLAG_ALLOW_REPLACEMENT: c_int = 1;
pub const DBUS_NAME_FLAG_REPLACE_EXISTING: c_int = 2;
pub const DBUS_NAME_FLAG_DO_NOT_QUEUE: c_int = 4;
pub const DBUS_WATCH_READABLE: c_int = 1;
pub const DBUS_WATCH_WRITABLE: c_int = 2;
pub const DBUS_WATCH_ERROR: c_int = 4;
pub const DBUS_WATCH_HANGUP: c_int = 8;
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusRequestNameReply {
PrimaryOwner = 1,
InQueue = 2,
Exists = 3,
AlreadyOwner = 4,
}
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusReleaseNameReply {
Released = 1,
NonExistent = 2,
NotOwner = 3,
}
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusHandlerResult {
Handled = 0,
NotYetHandled = 1,
NeedMemory = 2,
}
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusMessageType {
Invalid = 0,
MethodCall = 1,
MethodReturn = 2,
Error = 3,
Signal = 4,
}
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DBusDispatchStatus {
DataRemains = 0,
Complete = 1,
NeedMemory = 2,
}
#[repr(C)]
pub struct DBusError {
pub name: *const c_char,
pub message: *const c_char,
pub dummy: c_uint,
pub padding1: *const c_void
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct DBusMessageIter {
pub dummy1: *mut c_void,
pub dummy2: *mut c_void,
pub dummy3: u32,
pub dummy4: c_int,
pub dummy5: c_int,
pub dummy6: c_int,
pub dummy7: c_int,
pub dummy8: c_int,
pub dummy9: c_int,
pub dummy10: c_int,
pub dummy11: c_int,
pub pad1: c_int,
pub pad2: c_int,
// Here would have been padding; because pad3 is a 8 byte aligned pointer (on amd64).
// Rust reserves the right not to copy the padding when cloning a struct,
// but the D-Bus library uses this part of the struct too.
// Hence, add a field as big as the padding to ensure Rust copies all data.
pub pad2_added_by_rust: c_int,
pub pad3: *mut c_void,
}
pub type DBusHandleMessageFunction = Option<extern fn(conn: *mut DBusConnection, msg: *mut DBusMessage, user_data: *mut c_void) -> DBusHandlerResult>;
pub type DBusAddWatchFunction = Option<extern fn(watch: *mut DBusWatch, user_data: *mut c_void) -> u32>;
pub type DBusRemoveWatchFunction = Option<extern fn(watch: *mut DBusWatch, user_data: *mut c_void)>;
pub type DBusWatchToggledFunction = Option<extern fn(watch: *mut DBusWatch, user_data: *mut c_void)>;
pub type DBusAddTimeoutFunction = Option<extern fn(timeout: *mut DBusTimeout, user_data: *mut c_void) -> u32>;
pub type DBusTimeoutToggledFunction = Option<extern fn(timeout: *mut DBusTimeout, user_data: *mut c_void)>;
pub type DBusRemoveTimeoutFunction = Option<extern fn(timeout: *mut DBusTimeout, user_data: *mut c_void)>;
pub type DBusDispatchStatusFunction = Option<extern fn(conn: *mut DBusConnection, new_status: DBusDispatchStatus, user_data: *mut c_void)>;
pub type DBusWakeupMainFunction = Option<extern fn(conn: *mut DBusConnection, user_data: *mut c_void)>;
pub type DBusPendingCallNotifyFunction = Option<extern fn(pending: *mut DBusPendingCall, user_data: *mut c_void)>;
pub type DBusFreeFunction = Option<extern fn(memory: *mut c_void)>;
#[repr(C)]
pub struct DBusObjectPathVTable {
pub unregister_function: Option<extern fn(conn: *mut DBusConnection, user_data: *mut c_void)>,
pub message_function: DBusHandleMessageFunction,
pub dbus_internal_pad1: Option<extern fn()>,
pub dbus_internal_pad2: Option<extern fn()>,
pub dbus_internal_pad3: Option<extern fn()>,
pub dbus_internal_pad4: Option<extern fn()>,
}
extern "C" {
pub fn dbus_bus_get_private(t: DBusBusType, error: *mut DBusError) -> *mut DBusConnection;
pub fn dbus_bus_get_unique_name(conn: *mut DBusConnection) -> *const c_char;
pub fn dbus_bus_request_name(conn: *mut DBusConnection, name: *const c_char,
flags: c_uint, error: *mut DBusError) -> c_int;
pub fn dbus_bus_release_name(conn: *mut DBusConnection, name: *const c_char,
error: *mut DBusError) -> c_int;
pub fn dbus_bus_add_match(conn: *mut DBusConnection, rule: *const c_char,
error: *mut DBusError);
pub fn dbus_bus_remove_match(conn: *mut DBusConnection, rule: *const c_char,
error: *mut DBusError);
pub fn dbus_bus_register(conn: *mut DBusConnection, error: *mut DBusError) -> bool;
pub fn dbus_connection_close(conn: *mut DBusConnection);
pub fn dbus_connection_dispatch(conn: *mut DBusConnection) -> DBusDispatchStatus;
pub fn dbus_connection_flush(conn: *mut DBusConnection);
pub fn dbus_connection_open_private(address: *const c_char, error: *mut DBusError) -> *mut DBusConnection;
pub fn dbus_connection_unref(conn: *mut DBusConnection);
pub fn dbus_connection_get_is_connected(conn: *mut DBusConnection) -> bool;
pub fn dbus_connection_set_exit_on_disconnect(conn: *mut DBusConnection, enable: u32);
pub fn dbus_connection_send_with_reply_and_block(conn: *mut DBusConnection,
message: *mut DBusMessage, timeout_milliseconds: c_int, error: *mut DBusError) -> *mut DBusMessage;
pub fn dbus_connection_send_with_reply(conn: *mut DBusConnection,
message: *mut DBusMessage, pending_return: *mut *mut DBusPendingCall, timeout_milliseconds: c_int) -> u32;
pub fn dbus_connection_send(conn: *mut DBusConnection,
message: *mut DBusMessage, serial: *mut u32) -> u32;
pub fn dbus_connection_read_write_dispatch(conn: *mut DBusConnection,
timeout_milliseconds: c_int) -> u32;
pub fn dbus_connection_try_register_object_path(conn: *mut DBusConnection,
path: *const c_char, vtable: *const DBusObjectPathVTable, user_data: *mut c_void,
error: *mut DBusError) -> u32;
pub fn dbus_connection_unregister_object_path(conn: *mut DBusConnection,
path: *const c_char) -> u32;
pub fn dbus_connection_list_registered(conn: *mut DBusConnection,
parent_path: *const c_char, child_entries: *mut *mut *mut c_char) -> u32;
pub fn dbus_connection_add_filter(conn: *mut DBusConnection, function: DBusHandleMessageFunction,
user_data: *mut c_void, free_data_function: DBusFreeFunction) -> u32;
pub fn dbus_connection_remove_filter(conn: *mut DBusConnection, function: DBusHandleMessageFunction,
user_data: *mut c_void) -> u32;
pub fn dbus_connection_set_watch_functions(conn: *mut DBusConnection, add_function: DBusAddWatchFunction,
remove_function: DBusRemoveWatchFunction, toggled_function: DBusWatchToggledFunction,
data: *mut c_void, free_data_function: DBusFreeFunction) -> u32;
pub fn dbus_connection_set_timeout_functions(conn: *mut DBusConnection, add_function: DBusAddTimeoutFunction,
remove_function: DBusRemoveTimeoutFunction, toggled_function: DBusTimeoutToggledFunction,
data: *mut c_void, free_data_function: DBusFreeFunction) -> u32;
pub fn dbus_connection_set_dispatch_status_function(conn: *mut DBusConnection,
dispatch_function: DBusDispatchStatusFunction, data: *mut c_void, free_data_function: DBusFreeFunction);
pub fn dbus_connection_set_wakeup_main_function(conn: *mut DBusConnection,
wakeup_function: DBusWakeupMainFunction, data: *mut c_void, free_data_function: DBusFreeFunction);
pub fn dbus_error_init(error: *mut DBusError);
pub fn dbus_error_free(error: *mut DBusError);
pub fn dbus_set_error(error: *mut DBusError, name: *const c_char, message: *const c_char, ...);
pub fn dbus_set_error_from_message(error: *mut DBusError, message: *mut DBusMessage) -> u32;
pub fn dbus_message_new_method_call(destination: *const c_char, path: *const c_char,
iface: *const c_char, method: *const c_char) -> *mut DBusMessage;
pub fn dbus_message_new_method_return(message: *mut DBusMessage) -> *mut DBusMessage;
pub fn dbus_message_new_error(message: *mut DBusMessage,
error_name: *const c_char, error_message: *const c_char) -> *mut DBusMessage;
pub fn dbus_message_new_signal(path: *const c_char,
iface: *const c_char, name: *const c_char) -> *mut DBusMessage;
pub fn dbus_message_ref(message: *mut DBusMessage) -> *mut DBusMessage;
pub fn dbus_message_unref(message: *mut DBusMessage);
pub fn dbus_message_get_type(message: *mut DBusMessage) -> c_int;
pub fn dbus_message_is_method_call(message: *mut DBusMessage, iface: *const c_char, method: *const c_char) -> u32;
pub fn dbus_message_is_signal(message: *mut DBusMessage, iface: *const c_char, signal_name: *const c_char) -> u32;
pub fn dbus_message_get_reply_serial(message: *mut DBusMessage) -> u32;
pub fn dbus_message_get_serial(message: *mut DBusMessage) -> u32;
pub fn dbus_message_get_path(message: *mut DBusMessage) -> *const c_char;
pub fn dbus_message_get_interface(message: *mut DBusMessage) -> *const c_char;
pub fn dbus_message_get_destination(message: *mut DBusMessage) -> *const c_char;
pub fn dbus_message_get_member(message: *mut DBusMessage) -> *const c_char;
pub fn dbus_message_get_sender(message: *mut DBusMessage) -> *const c_char;
pub fn dbus_message_set_serial(message: *mut DBusMessage, serial: u32);
pub fn dbus_message_set_destination(message: *mut DBusMessage, destination: *const c_char) -> u32;
pub fn dbus_message_get_no_reply(message: *mut DBusMessage) -> u32;
pub fn dbus_message_set_no_reply(message: *mut DBusMessage, no_reply: u32);
pub fn dbus_message_get_auto_start(message: *mut DBusMessage) -> u32;
pub fn dbus_message_set_auto_start(message: *mut DBusMessage, no_reply: u32);
pub fn dbus_message_iter_append_basic(iter: *mut DBusMessageIter, t: c_int, value: *const c_void) -> u32;
pub fn dbus_message_iter_append_fixed_array(iter: *mut DBusMessageIter, element_type: c_int,
value: *const c_void, n_elements: c_int) -> u32;
pub fn dbus_message_iter_init(message: *mut DBusMessage, iter: *mut DBusMessageIter) -> u32;
pub fn dbus_message_iter_init_append(message: *mut DBusMessage, iter: *mut DBusMessageIter);
pub fn dbus_message_iter_get_arg_type(iter: *mut DBusMessageIter) -> c_int;
pub fn dbus_message_iter_get_basic(iter: *mut DBusMessageIter, value: *mut c_void);
pub fn dbus_message_iter_get_element_type(iter: *mut DBusMessageIter) -> c_int;
pub fn dbus_message_iter_get_fixed_array(iter: *mut DBusMessageIter,
value: *mut c_void, n_elements: *mut c_int) -> u32;
pub fn dbus_message_iter_get_signature(iter: *mut DBusMessageIter) -> *mut c_char;
pub fn dbus_message_iter_next(iter: *mut DBusMessageIter) -> u32;
pub fn dbus_message_iter_recurse(iter: *mut DBusMessageIter, subiter: *mut DBusMessageIter);
pub fn dbus_message_iter_open_container(iter: *mut DBusMessageIter, _type: c_int,
contained_signature: *const c_char, sub: *mut DBusMessageIter) -> u32;
pub fn dbus_message_iter_close_container(iter: *mut DBusMessageIter, sub: *mut DBusMessageIter) -> u32;
pub fn dbus_free(memory: *mut c_void);
pub fn dbus_free_string_array(str_array: *mut *mut c_char) -> c_void;
pub fn dbus_signature_validate_single(signature: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_threads_init_default() -> c_int;
pub fn dbus_validate_bus_name(busname: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_validate_error_name(errorname: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_validate_interface(interface: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_validate_member(member: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_validate_path(path: *const c_char, error: *mut DBusError) -> u32;
pub fn dbus_watch_get_enabled(watch: *mut DBusWatch) -> u32;
pub fn dbus_watch_get_flags(watch: *mut DBusWatch) -> c_uint;
pub fn dbus_watch_get_unix_fd(watch: *mut DBusWatch) -> c_int;
pub fn dbus_watch_handle(watch: *mut DBusWatch, flags: c_uint) -> u32;
pub fn dbus_watch_get_data(watch: *mut DBusWatch) -> *mut c_void;
pub fn dbus_watch_set_data(watch: *mut DBusWatch, user_data: *mut c_void,
free_data_function: DBusFreeFunction);
pub fn dbus_timeout_get_enabled(timeout: *mut DBusTimeout) -> u32;
pub fn dbus_timeout_get_interval(timeout: *mut DBusTimeout) -> c_int;
pub fn dbus_timeout_handle(timeout: *mut DBusTimeout) -> u32;
pub fn dbus_timeout_get_data(timeout: *mut DBusTimeout) -> *mut c_void;
pub fn dbus_timeout_set_data(timeout: *mut DBusTimeout, user_data: *mut c_void,
free_data_function: DBusFreeFunction);
pub fn dbus_pending_call_ref(pending: *mut DBusPendingCall) -> *mut DBusPendingCall;
pub fn dbus_pending_call_unref(pending: *mut DBusPendingCall);
pub fn dbus_pending_call_set_notify(pending: *mut DBusPendingCall, n: DBusPendingCallNotifyFunction,
user_data: *mut c_void, free_user_data: DBusFreeFunction) -> u32;
pub fn dbus_pending_call_steal_reply(pending: *mut DBusPendingCall) -> *mut DBusMessage;
pub fn dbus_message_marshal(msg: *mut DBusMessage, marshalled_data_p: *mut *mut c_char, len_p: *mut c_int) -> u32;
pub fn dbus_message_demarshal(s: *const c_char, len: c_int, error: *mut DBusError) -> *mut DBusMessage;
pub fn dbus_message_demarshal_bytes_needed(buf: *const c_char, len: c_int) -> c_int;
pub fn dbus_connection_set_max_message_size(conn: *mut DBusConnection, size: c_long);
pub fn dbus_connection_get_max_message_size(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_set_max_message_unix_fds(conn: *mut DBusConnection, n: c_long);
pub fn dbus_connection_get_max_message_unix_fds(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_set_max_received_size(conn: *mut DBusConnection, size: c_long);
pub fn dbus_connection_get_max_received_size(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_set_max_received_unix_fds(conn: *mut DBusConnection, n: c_long);
pub fn dbus_connection_get_max_received_unix_fds(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_get_outgoing_size(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_get_outgoing_unix_fds(conn: *mut DBusConnection) -> c_long;
pub fn dbus_connection_has_messages_to_send(conn: *mut DBusConnection) -> u32;
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"43cd097ac12109401eff2dda98d0b46064ad8415ea6e1a0a9381869938a4348c","LICENSE.md":"399507a62fba271ddb3e24dc857e85b571fbb76435546f51b212cf04d8463f58","README.md":"721e4f3fe70db2cabfb05367d2a341d071b589f7387d609b2e5edefb7f91db4f","examples/dump_process_registers.rs":"9bb011138980efda1bc24fb27bb582f4a6f175444b518c5c52d94e74282d8f21","src/boolean.rs":"1d24ea9872748881cd7269a383a7c344e3a650df23f0e44e3b6c266fb8205d9a","src/bootstrap.rs":"f197811f56bc633410dabfd2156e3ae17f50b3ff51329314e558c3c80e00d0e2","src/clock_types.rs":"3ccf57f85d30766b1c243357dbd5a86b6dda0ce9084da25a1ed139cf506859e0","src/kern_return.rs":"18bff1c0f47ac5f4f754b66ab7e09265acd43b1bfdac773be938c33d9decfe85","src/lib.rs":"2cf5554ea70b4c180eadbae651fbeb87b9e842e2ee51e53f3f3ff339cd6b8478","src/mach_port.rs":"7a89693d21575923c0e9967876546f64c4f4defa2438e2ef7cad220614c56875","src/mach_types.rs":"0d7699edef5468c5d3f5fe841351efdd7e28e1fd2679ecc4a8583f6cd12369f8","src/memory_object_types.rs":"3805f6076131a98b0a5607cf9420cc8248fe2b9ac6afd06c21ebe1e5ed3329f4","src/message.rs":"393dd1d6149e5219099f776f5a7d2d101cccf0c50dff38de3578c0d0b3ab2583","src/port.rs":"1a0a3659a92aca0b02ec3388dfea7a8f385ab9471c5d17ac166eb2310adfb6c9","src/structs.rs":"f6abc0adf79831f1ace6b606de39ac0aa9211033b4a2d3307545b09305d8eeb3","src/task.rs":"097bec27fefd7e17bf1b465ccaf1ad2c649438f66d2cb3f23b6b9d7ae72362d2","src/task_info.rs":"34856be5eb0a57bffa965a7e0b15337a23b1c73303387604af6b8d493e592451","src/thread_act.rs":"e70ed8f18fd303ffb724e9f52959c6b10f71dd81e2f283c81b4c2ec0d1521d17","src/thread_status.rs":"a900380c6743b77525ac0eb79f8155f8fe37eae13d93c09737d437e426b39053","src/traps.rs":"73d8d45ba97acbfad5e5f65233c114732c8e7dd90aebefd9e3c7c2604817e491","src/types.rs":"92e1fa7a09d068b0eabb32099018cddca8080ab3d7ff444dbdab87f138c52a6d","src/vm.rs":"e732dfb766500cafe159be0f2a418d73950a556801799d3b6a57792b4dac6b74","src/vm_attributes.rs":"2933380b6ac2bc8892923946d4484f481e30a2cc80a055ca64801d3497318ad1","src/vm_behavior.rs":"746eee444987a0292393e066fa30e83bbffb8fe91b273d6633f1536c3406cd6e","src/vm_inherit.rs":"fdbf7320faa3cfa73f8cf1d1e549460f370eca9ad9c27e04eedf8f2fc36cbb67","src/vm_page_size.rs":"7a6e7f6aa82a4e8962aa50a44484edc33ed1a9c02fa11b2f3b2425013acbb074","src/vm_prot.rs":"2372650264dc27d04fb90d6e548addacb923bfc813a4e5f0f836257e4d114aeb","src/vm_purgable.rs":"acd54e47f8a3a6aa20ca884da7e4a3cf5cc294ecc1c483987416b389fe5fdcbc","src/vm_region.rs":"e7eec2ef80a65f67992f10e9d6779779caea76f417b0c8448cdc8188cfa81f51","src/vm_statistics.rs":"2043854845f9fbc152698d61fb917284600f8cf573cbed45e05d047405831e26","src/vm_sync.rs":"c782a5a3f417532beef1480a1961d8215d4be7b30877ec3c56273cbbfbf68930","src/vm_types.rs":"5a0f21a8e54fab48af5c07f4ab3692dfe812a14534959d478bdf4cb10b5fa6b1"},"package":"2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"}

22
third_party/rust/mach/Cargo.toml vendored Normal file
View File

@ -0,0 +1,22 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "mach"
version = "0.1.2"
authors = ["Nick Fitzgerald <fitzgen@gmail.com>", "David Cuddeback <david.cuddeback@gmail.com>"]
description = "A Rust interface to the Mach 3.0 kernel that underlies OSX."
readme = "README.md"
license = "BSD-2-Clause"
repository = "https://github.com/fitzgen/mach"
[dependencies.libc]
version = "0.2"

23
third_party/rust/mach/LICENSE.md vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2015, Nick Fitzgerald
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

3
third_party/rust/mach/README.md vendored Normal file
View File

@ -0,0 +1,3 @@
[![Build Status](https://travis-ci.org/fitzgen/mach.png?branch=master)](https://travis-ci.org/fitzgen/mach)
A rust interface to the Mach 3.0 kernel that underlies OSX.

View File

@ -0,0 +1,129 @@
//! A script to read and dump to stdout the current register values of a
//! process.
extern crate libc;
extern crate mach;
use std::io;
use std::mem;
use std::ptr;
use mach::kern_return::{KERN_SUCCESS};
use mach::message::{mach_msg_type_number_t};
use mach::port::{mach_port_name_t};
use mach::structs::{x86_thread_state64_t};
use mach::task::{task_resume, task_suspend, task_threads};
use mach::thread_act::{thread_get_state};
use mach::thread_status::{x86_THREAD_STATE64};
use mach::traps::{mach_task_self, task_for_pid};
use mach::types::{task_t, thread_act_array_t};
use std::io::prelude::*;
fn read_int() -> Result<::libc::c_int, ()> {
let stdin = io::stdin();
let mut line = String::new();
stdin.read_line(&mut line).ok().unwrap();
let mut value : ::libc::c_int = 0;
for c in line.chars().take_while(|&c| c != '\n') {
if let Some(d) = c.to_digit(10) {
value = value * 10 + (d as ::libc::c_int);
} else {
return Err(());
}
}
return Ok(value);
}
fn resume(task: task_t) {
unsafe {
let kret = task_resume(task);
if kret != KERN_SUCCESS {
println!("Did not succeed in resuming task.");
println!("kern_return_t error {}", kret);
panic!();
}
}
}
fn main() {
print!("Enter pid: ");
io::stdout().flush().ok();
let pid = match read_int() {
Ok(v) => v,
Err(_) => {
println!("Bad pid!");
return;
},
};
println!("pid = {}", &pid);
let task : mach_port_name_t = 0;
unsafe {
let kret = task_for_pid(mach_task_self() as mach_port_name_t,
pid,
mem::transmute(&task));
if kret != KERN_SUCCESS {
println!("Did not succeed in getting task for pid {}", pid);
println!("kern_return_t error {}", kret);
println!("");
println!("Did you forget to run with 'sudo'? This script will");
println!("probably fail without it.");
return;
}
}
println!("task = 0x{:x}", &task);
unsafe {
let kret = task_suspend(task as task_t);
if kret != KERN_SUCCESS {
println!("Did not succeed in suspending task.");
println!("kern_return_t error {}", kret);
return;
}
}
let thread_list : thread_act_array_t = ptr::null_mut();
let thread_count : mach_msg_type_number_t = 0;
unsafe {
let kret = task_threads(task as task_t,
mem::transmute(&thread_list),
mem::transmute(&thread_count));
if kret != KERN_SUCCESS {
println!("Did not succeed in getting task's threads");
println!("kern_return_t error {}", kret);
resume(task as task_t);
return;
}
}
println!("Task is running {} threads", &thread_count);
unsafe {
let threads = Vec::from_raw_parts(thread_list, thread_count as usize, thread_count as usize);
let state = x86_thread_state64_t::new();
let state_count = x86_thread_state64_t::count();
for (idx, &thread) in threads.iter().enumerate() {
println!("Thread {}:", idx);
let kret = thread_get_state(thread,
x86_THREAD_STATE64,
mem::transmute(&state),
mem::transmute(&state_count));
if kret != KERN_SUCCESS {
println!("Did not succeed in getting task's thread state");
println!("kern_return_t error {}", kret);
continue;
}
println!("{:?}", state);
}
}
resume(task as task_t);
println!("Success!");
}

7
third_party/rust/mach/src/boolean.rs vendored Normal file
View File

@ -0,0 +1,7 @@
//! This module corresponds to `mach/i386/boolean.h`.
#[cfg(target_arch = "x86_64")]
pub type boolean_t = ::libc::c_uint;
#[cfg(not(target_arch = "x86_64"))]
pub type boolean_t = ::libc::c_int;

14
third_party/rust/mach/src/bootstrap.rs vendored Normal file
View File

@ -0,0 +1,14 @@
//! This module corresponds to `bootstrap.h`
use kern_return::{kern_return_t};
use libc;
use port::{mach_port_t};
pub const BOOTSTRAP_MAX_NAME_LEN: libc::c_uint = 128;
extern "C" {
pub fn bootstrap_look_up(bp: mach_port_t,
service_name: *const libc::c_char,
sp: *mut mach_port_t)
-> kern_return_t;
}

View File

@ -0,0 +1,15 @@
//! This module roughly corresponds to `mach/clock_types.h`.
pub type alarm_type_t = ::libc::c_int;
pub type sleep_type_t = ::libc::c_int;
pub type clock_id_t = ::libc::c_int;
pub type clock_flavor_t = ::libc::c_int;
pub type clock_attr_t = *mut ::libc::c_int;
pub type clock_res_t = ::libc::c_int;
#[repr(C)]
pub struct mach_timespec {
tv_sec: ::libc::c_uint,
tv_nsec: clock_res_t
}
pub type mach_timespec_t = mach_timespec;

View File

@ -0,0 +1,58 @@
//! This module corresponds to `mach/kern_return.h` and
//! `mach/i386/kern_return.h`.
pub type kern_return_t = ::libc::c_int;
pub const KERN_SUCCESS : kern_return_t = 0;
pub const KERN_INVALID_ADDRESS : kern_return_t = 1;
pub const KERN_PROTECTION_FAILURE : kern_return_t = 2;
pub const KERN_NO_SPACE : kern_return_t = 3;
pub const KERN_INVALID_ARGUMENT : kern_return_t = 4;
pub const KERN_FAILURE : kern_return_t = 5;
pub const KERN_RESOURCE_SHORTAGE : kern_return_t = 6;
pub const KERN_NOT_RECEIVER : kern_return_t = 7;
pub const KERN_NO_ACCESS : kern_return_t = 8;
pub const KERN_MEMORY_FAILURE : kern_return_t = 9;
pub const KERN_MEMORY_ERROR : kern_return_t = 10;
pub const KERN_ALREADY_IN_SET : kern_return_t = 11;
pub const KERN_NOT_IN_SET : kern_return_t = 12;
pub const KERN_NAME_EXISTS : kern_return_t = 13;
pub const KERN_ABORTED : kern_return_t = 14;
pub const KERN_INVALID_NAME : kern_return_t = 15;
pub const KERN_INVALID_TASK : kern_return_t = 16;
pub const KERN_INVALID_RIGHT : kern_return_t = 17;
pub const KERN_INVALID_VALUE : kern_return_t = 18;
pub const KERN_UREFS_OVERFLOW : kern_return_t = 19;
pub const KERN_INVALID_CAPABILITY : kern_return_t = 20;
pub const KERN_RIGHT_EXISTS : kern_return_t = 21;
pub const KERN_INVALID_HOST : kern_return_t = 22;
pub const KERN_MEMORY_PRESENT : kern_return_t = 23;
pub const KERN_MEMORY_DATA_MOVED : kern_return_t = 24;
pub const KERN_MEMORY_RESTART_COPY : kern_return_t = 25;
pub const KERN_INVALID_PROCESSOR_SET : kern_return_t = 26;
pub const KERN_POLICY_LIMIT : kern_return_t = 27;
pub const KERN_INVALID_POLICY : kern_return_t = 28;
pub const KERN_INVALID_OBJECT : kern_return_t = 29;
pub const KERN_ALREADY_WAITING : kern_return_t = 30;
pub const KERN_DEFAULT_SET : kern_return_t = 31;
pub const KERN_EXCEPTION_PROTECTED : kern_return_t = 32;
pub const KERN_INVALID_LEDGER : kern_return_t = 33;
pub const KERN_INVALID_MEMORY_CONTROL : kern_return_t = 34;
pub const KERN_INVALID_SECURITY : kern_return_t = 35;
pub const KERN_NOT_DEPRESSED : kern_return_t = 36;
pub const KERN_TERMINATED : kern_return_t = 37;
pub const KERN_LOCK_SET_DESTROYED : kern_return_t = 38;
pub const KERN_LOCK_UNSTABLE : kern_return_t = 39;
pub const KERN_LOCK_OWNED : kern_return_t = 40;
pub const KERN_LOCK_OWNED_SELF : kern_return_t = 41;
pub const KERN_SEMAPHORE_DESTROYED : kern_return_t = 42;
pub const KERN_RPC_SERVER_TERMINATED : kern_return_t = 43;
pub const KERN_RPC_TERMINATE_ORPHAN : kern_return_t = 44;
pub const KERN_RPC_CONTINUE_ORPHAN : kern_return_t = 45;
pub const KERN_NOT_SUPPORTED : kern_return_t = 46;
pub const KERN_NODE_DOWN : kern_return_t = 47;
pub const KERN_NOT_WAITING : kern_return_t = 48;
pub const KERN_OPERATION_TIMED_OUT : kern_return_t = 49;
pub const KERN_CODESIGN_ERROR : kern_return_t = 50;
pub const KERN_POLICY_STATIC : kern_return_t = 51;
pub const KERN_RETURN_MAX : kern_return_t = 0x100;

32
third_party/rust/mach/src/lib.rs vendored Normal file
View File

@ -0,0 +1,32 @@
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
extern crate libc;
pub mod boolean;
pub mod bootstrap;
pub mod clock_types;
pub mod kern_return;
pub mod mach_port;
pub mod mach_types;
pub mod memory_object_types;
pub mod message;
pub mod port;
pub mod structs;
pub mod task;
pub mod task_info;
pub mod thread_act;
pub mod thread_status;
pub mod traps;
pub mod types;
pub mod vm;
pub mod vm_attributes;
pub mod vm_behavior;
pub mod vm_inherit;
pub mod vm_page_size;
pub mod vm_prot;
pub mod vm_purgable;
pub mod vm_region;
pub mod vm_statistics;
pub mod vm_sync;
pub mod vm_types;

22
third_party/rust/mach/src/mach_port.rs vendored Normal file
View File

@ -0,0 +1,22 @@
//! This module corresponds to `mach/mach_port.h`
use kern_return::{kern_return_t};
use message::{mach_msg_type_name_t};
use port::{mach_port_name_t, mach_port_right_t, mach_port_t};
use types::{ipc_space_t};
extern "C" {
pub fn mach_port_allocate(task: ipc_space_t, right: mach_port_right_t,
name: *mut mach_port_name_t) -> kern_return_t;
pub fn mach_port_destroy(task: ipc_space_t,
name: mach_port_name_t) -> kern_return_t;
pub fn mach_port_deallocate(task: ipc_space_t,
name: mach_port_name_t) -> kern_return_t;
pub fn mach_port_insert_right(task: ipc_space_t, name: mach_port_name_t,
poly: mach_port_t,
polyPoly: mach_msg_type_name_t) -> kern_return_t;
pub fn mach_port_extract_right(task: ipc_space_t, name: mach_port_name_t,
msgt_name: mach_msg_type_name_t,
poly: *mut mach_port_t,
polyPoly: *mut mach_msg_type_name_t) -> kern_return_t;
}

View File

@ -0,0 +1,3 @@
use port::mach_port_t;
pub type task_name_t = mach_port_t;

View File

@ -0,0 +1,9 @@
//! This module roughly corresponds to `mach/memory_object_types.h`.
use vm_types::{natural_t};
pub type memory_object_offset_t = ::libc::c_ulonglong;
pub type memory_object_size_t = ::libc::c_ulonglong;
pub type memory_object_cluster_size_t = natural_t;
pub type memory_object_fault_info_t = *mut natural_t;
pub type vm_object_id_t = ::libc::c_ulonglong;

248
third_party/rust/mach/src/message.rs vendored Normal file
View File

@ -0,0 +1,248 @@
//! This module corresponds to `mach/message.h`.
use std::os::raw::{c_uint, c_void};
use kern_return::{kern_return_t};
use port::{mach_port_name_t, mach_port_t};
use vm_types::{integer_t, natural_t};
pub type mach_msg_timeout_t = natural_t;
pub type mach_msg_bits_t = c_uint;
pub type mach_msg_id_t = integer_t;
pub type mach_msg_size_t = natural_t;
pub type mach_msg_copy_options_t = c_uint;
pub type mach_msg_descriptor_type_t = c_uint;
pub type mach_msg_type_name_t = c_uint;
pub type mach_msg_trailer_type_t = c_uint;
pub type mach_msg_trailer_size_t = c_uint;
pub type mach_msg_option_t = integer_t;
pub type mach_msg_type_number_t = natural_t;
pub type mach_msg_type_size_t = natural_t;
pub type mach_msg_return_t = kern_return_t;
pub const MACH_MSG_TIMEOUT_NONE: mach_msg_timeout_t = 0;
pub const MACH_MSGH_BITS_ZERO: mach_msg_bits_t = 0x00000000;
pub const MACH_MSGH_BITS_REMOTE_MASK: mach_msg_bits_t = 0x0000001f;
pub const MACH_MSGH_BITS_LOCAL_MASK: mach_msg_bits_t = 0x00001f00;
pub const MACH_MSGH_BITS_VOUCHER_MASK: mach_msg_bits_t = 0x001f0000;
pub const MACH_MSGH_BITS_PORTS_MASK: mach_msg_bits_t =
MACH_MSGH_BITS_REMOTE_MASK | MACH_MSGH_BITS_LOCAL_MASK | MACH_MSGH_BITS_VOUCHER_MASK;
pub const MACH_MSGH_BITS_COMPLEX: mach_msg_bits_t = 0x80000000;
pub const MACH_MSGH_BITS_USER: mach_msg_bits_t = 0x801f1f1f;
#[allow(non_snake_case)]
pub fn MACH_MSGH_BITS(remote: mach_msg_bits_t, local: mach_msg_bits_t) -> mach_msg_bits_t {
remote | (local << 8)
}
pub const MACH_MSG_TYPE_MOVE_RECEIVE : mach_msg_type_name_t = 16;
pub const MACH_MSG_TYPE_MOVE_SEND : mach_msg_type_name_t = 17;
pub const MACH_MSG_TYPE_MOVE_SEND_ONCE : mach_msg_type_name_t = 18;
pub const MACH_MSG_TYPE_COPY_SEND : mach_msg_type_name_t = 19;
pub const MACH_MSG_TYPE_MAKE_SEND : mach_msg_type_name_t = 20;
pub const MACH_MSG_TYPE_MAKE_SEND_ONCE : mach_msg_type_name_t = 21;
pub const MACH_MSG_TYPE_COPY_RECEIVE : mach_msg_type_name_t = 22;
pub const MACH_MSG_TYPE_DISPOSE_RECEIVE : mach_msg_type_name_t = 24;
pub const MACH_MSG_TYPE_DISPOSE_SEND : mach_msg_type_name_t = 25;
pub const MACH_MSG_TYPE_DISPOSE_SEND_ONCE : mach_msg_type_name_t = 26;
pub const MACH_MSG_PHYSICAL_COPY: mach_msg_copy_options_t = 0;
pub const MACH_MSG_VIRTUAL_COPY: mach_msg_copy_options_t = 1;
pub const MACH_MSG_ALLOCATE: mach_msg_copy_options_t = 2;
pub const MACH_MSG_PORT_DESCRIPTOR: mach_msg_descriptor_type_t = 0;
pub const MACH_MSG_OOL_DESCRIPTOR: mach_msg_descriptor_type_t = 1;
pub const MACH_MSG_OOL_PORTS_DESCRIPTOR: mach_msg_descriptor_type_t = 2;
pub const MACH_MSG_OOL_VOLATILE_DESCRIPTOR: mach_msg_descriptor_type_t = 3;
pub const MACH_MSG_OPTION_NONE: mach_msg_option_t = 0x00000000;
pub const MACH_SEND_MSG: mach_msg_option_t = 0x00000001;
pub const MACH_RCV_MSG: mach_msg_option_t = 0x00000002;
pub const MACH_RCV_LARGE: mach_msg_option_t = 0x00000004;
pub const MACH_RCV_LARGE_IDENTITY: mach_msg_option_t = 0x00000008;
pub const MACH_SEND_TIMEOUT: mach_msg_option_t = 0x00000010;
pub const MACH_SEND_INTERRUPT: mach_msg_option_t = 0x00000040;
pub const MACH_SEND_NOTIFY: mach_msg_option_t = 0x00000080;
pub const MACH_SEND_ALWAYS: mach_msg_option_t = 0x00010000;
pub const MACH_SEND_TRAILER: mach_msg_option_t = 0x00020000;
pub const MACH_SEND_NOIMPORTANCE: mach_msg_option_t = 0x00040000;
pub const MACH_SEND_NODENAP: mach_msg_option_t = MACH_SEND_NOIMPORTANCE;
pub const MACH_SEND_IMPORTANCE: mach_msg_option_t = 0x00080000;
pub const MACH_RCV_TIMEOUT: mach_msg_option_t = 0x00000100;
pub const MACH_RCV_NOTIFY: mach_msg_option_t = 0x00000200;
pub const MACH_RCV_INTERRUPT: mach_msg_option_t = 0x00000400;
pub const MACH_RCV_VOUCHER: mach_msg_option_t = 0x00000800;
pub const MACH_RCV_OVERWRITE: mach_msg_option_t = 0x00001000;
pub const MACH_MSG_SUCCESS: mach_msg_return_t = 0x00000000;
pub const MACH_MSG_MASK: mach_msg_return_t = 0x00003e00;
pub const MACH_MSG_IPC_SPACE: mach_msg_return_t = 0x00002000;
pub const MACH_MSG_VM_SPACE: mach_msg_return_t = 0x00001000;
pub const MACH_MSG_IPC_KERNEL: mach_msg_return_t = 0x00000800;
pub const MACH_MSG_VM_KERNEL: mach_msg_return_t = 0x00000400;
pub const MACH_SEND_IN_PROGRESS: mach_msg_return_t = 0x10000001;
pub const MACH_SEND_INVALID_DATA: mach_msg_return_t = 0x10000002;
pub const MACH_SEND_INVALID_DEST: mach_msg_return_t = 0x10000003;
pub const MACH_SEND_TIMED_OUT: mach_msg_return_t = 0x10000004;
pub const MACH_SEND_INVALID_VOUCHER: mach_msg_return_t = 0x10000005;
pub const MACH_SEND_INTERRUPTED: mach_msg_return_t = 0x10000007;
pub const MACH_SEND_MSG_TOO_SMALL: mach_msg_return_t = 0x10000008;
pub const MACH_SEND_INVALID_REPLY: mach_msg_return_t = 0x10000009;
pub const MACH_SEND_INVALID_RIGHT: mach_msg_return_t = 0x1000000a;
pub const MACH_SEND_INVALID_NOTIFY: mach_msg_return_t = 0x1000000b;
pub const MACH_SEND_INVALID_MEMORY: mach_msg_return_t = 0x1000000c;
pub const MACH_SEND_NO_BUFFER: mach_msg_return_t = 0x1000000d;
pub const MACH_SEND_TOO_LARGE: mach_msg_return_t = 0x1000000e;
pub const MACH_SEND_INVALID_TYPE: mach_msg_return_t = 0x1000000f;
pub const MACH_SEND_INVALID_HEADER: mach_msg_return_t = 0x10000010;
pub const MACH_SEND_INVALID_TRAILER: mach_msg_return_t = 0x10000011;
pub const MACH_SEND_INVALID_RT_OOL_SIZE: mach_msg_return_t = 0x10000015;
pub const MACH_RCV_IN_PROGRESS: mach_msg_return_t = 0x10004001;
pub const MACH_RCV_INVALID_NAME: mach_msg_return_t = 0x10004002;
pub const MACH_RCV_TIMED_OUT: mach_msg_return_t = 0x10004003;
pub const MACH_RCV_TOO_LARGE: mach_msg_return_t = 0x10004004;
pub const MACH_RCV_INTERRUPTED: mach_msg_return_t = 0x10004005;
pub const MACH_RCV_PORT_CHANGED: mach_msg_return_t = 0x10004006;
pub const MACH_RCV_INVALID_NOTIFY: mach_msg_return_t = 0x10004007;
pub const MACH_RCV_INVALID_DATA: mach_msg_return_t = 0x10004008;
pub const MACH_RCV_PORT_DIED: mach_msg_return_t = 0x10004009;
pub const MACH_RCV_IN_SET: mach_msg_return_t = 0x1000400a;
pub const MACH_RCV_HEADER_ERROR: mach_msg_return_t = 0x1000400b;
pub const MACH_RCV_BODY_ERROR: mach_msg_return_t = 0x1000400c;
pub const MACH_RCV_INVALID_TYPE: mach_msg_return_t = 0x1000400d;
pub const MACH_RCV_SCATTER_SMALL: mach_msg_return_t = 0x1000400e;
pub const MACH_RCV_INVALID_TRAILER: mach_msg_return_t = 0x1000400f;
pub const MACH_RCV_IN_PROGRESS_TIMED: mach_msg_return_t = 0x10004011;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_header_t {
pub msgh_bits: mach_msg_bits_t,
pub msgh_size: mach_msg_size_t,
pub msgh_remote_port: mach_port_t,
pub msgh_local_port: mach_port_t,
pub msgh_voucher_port: mach_port_name_t,
pub msgh_id: mach_msg_id_t,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_body_t {
pub msgh_descriptor_count: mach_msg_size_t,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_base_t {
pub header: mach_msg_header_t,
pub body: mach_msg_body_t,
}
pub const MACH_MSG_TRAILER_FORMAT_0: mach_msg_trailer_type_t = 0;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_trailer_t {
pub msgh_trailer_type: mach_msg_trailer_type_t,
pub msgh_trailer_size: mach_msg_trailer_size_t,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_port_descriptor_t {
pub name: mach_port_t,
pub pad1: mach_msg_size_t,
pub pad2: u16,
pub disposition: u8, // mach_msg_type_name_t bitfield
pub type_: u8, // mach_msg_descriptor_type_t bitfield
}
impl mach_msg_port_descriptor_t {
pub fn new(name: mach_port_t, disposition: mach_msg_type_name_t) -> Self {
mach_msg_port_descriptor_t {
name: name,
pad1: 0,
pad2: 0,
disposition: disposition as u8,
type_: MACH_MSG_PORT_DESCRIPTOR as u8,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_ool_descriptor_t {
pub address: *mut c_void,
#[cfg(not(target_pointer_width = "64"))]
pub size: mach_msg_size_t,
pub deallocate: u8, // boolean_t bitfield
pub copy: u8, // mach_msg_copy_options_t bitfield
pub pad1: u8,
pub type_: u8, // mach_msg_descriptor_type_t bitfield
#[cfg(target_pointer_width = "64")]
pub size: mach_msg_size_t,
}
impl mach_msg_ool_descriptor_t {
pub fn new(address: *mut c_void,
deallocate: bool,
copy: mach_msg_copy_options_t,
size: u32)
-> Self {
mach_msg_ool_descriptor_t {
address: address,
deallocate: if deallocate { 1 } else { 0 },
copy: copy as u8,
pad1: 0,
type_: MACH_MSG_OOL_DESCRIPTOR as u8,
size: size,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_msg_ool_ports_descriptor_t {
pub address: *mut c_void,
#[cfg(not(target_pointer_width = "64"))]
pub count: mach_msg_size_t,
pub deallocate: u8, // boolean_t bitfield
pub copy: u8, // mach_msg_copy_options_t bitfield
pub disposition: u8, // mach_msg_type_name_t bitfield
pub type_: u8, // mach_msg_descriptor_type_t bitfield
#[cfg(target_pointer_width = "64")]
pub count: mach_msg_size_t,
}
extern "C" {
pub fn mach_msg(msg: *mut mach_msg_header_t,
option: mach_msg_option_t,
send_size: mach_msg_size_t,
recv_size: mach_msg_size_t,
recv_name: mach_port_name_t,
timeout: mach_msg_timeout_t,
notify: mach_port_name_t)
-> mach_msg_return_t;
// from mach/mach.h
pub fn mach_msg_send(msg: *mut mach_msg_header_t) -> mach_msg_return_t;
pub fn mach_msg_destroy(msg: *mut mach_msg_header_t);
}

24
third_party/rust/mach/src/port.rs vendored Normal file
View File

@ -0,0 +1,24 @@
//! This module corresponds to `mach/port.h`
use vm_types::{natural_t};
pub type mach_port_name_t = natural_t;
#[repr(C)]
pub struct ipc_port;
pub type ipc_port_t = *mut ipc_port;
pub type mach_port_t = ::libc::c_uint;
pub const MACH_PORT_NULL: mach_port_t = 0;
pub type mach_port_right_t = natural_t;
pub const MACH_PORT_RIGHT_SEND : mach_port_right_t = 0;
pub const MACH_PORT_RIGHT_RECEIVE : mach_port_right_t = 1;
pub const MACH_PORT_RIGHT_SEND_ONCE : mach_port_right_t = 2;
pub const MACH_PORT_RIGHT_PORT_SET : mach_port_right_t = 3;
pub const MACH_PORT_RIGHT_DEAD_NAME : mach_port_right_t = 4;
pub const MACH_PORT_RIGHT_LABELH : mach_port_right_t = 5;
pub const MACH_PORT_RIGHT_NUMBER : mach_port_right_t = 6;

65
third_party/rust/mach/src/structs.rs vendored Normal file
View File

@ -0,0 +1,65 @@
//! This module corresponds to `mach/_structs.h`.
use std::mem;
use message::{mach_msg_type_number_t};
#[repr(C)]
#[derive(Clone)]
#[derive(Debug)]
pub struct x86_thread_state64_t {
__rax: u64,
__rbx: u64,
__rcx: u64,
__rdx: u64,
__rdi: u64,
__rsi: u64,
__rbp: u64,
__rsp: u64,
__r8: u64,
__r9: u64,
__r10: u64,
__r11: u64,
__r12: u64,
__r13: u64,
__r14: u64,
__r15: u64,
__rip: u64,
__rflags: u64,
__cs: u64,
__fs: u64,
__gs: u64,
}
impl x86_thread_state64_t {
pub fn new() -> x86_thread_state64_t {
x86_thread_state64_t {
__rax: 0,
__rbx: 0,
__rcx: 0,
__rdx: 0,
__rdi: 0,
__rsi: 0,
__rbp: 0,
__rsp: 0,
__r8: 0,
__r9: 0,
__r10: 0,
__r11: 0,
__r12: 0,
__r13: 0,
__r14: 0,
__r15: 0,
__rip: 0,
__rflags: 0,
__cs: 0,
__fs: 0,
__gs: 0,
}
}
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<x86_thread_state64_t>() / mem::size_of::<::libc::c_int>())
as mach_msg_type_number_t
}
}

36
third_party/rust/mach/src/task.rs vendored Normal file
View File

@ -0,0 +1,36 @@
//! This module corresponds to `mach/task.defs`.
use kern_return::{kern_return_t};
use mach_types::task_name_t;
use message::{mach_msg_type_number_t};
use port::{mach_port_t};
use task_info::{task_flavor_t, task_info_t};
use types::{task_t, thread_act_array_t};
pub type task_special_port_t = ::std::os::raw::c_int;
pub const TASK_KERNEL_PORT: task_special_port_t = 1;
pub const TASK_HOST_PORT: task_special_port_t = 2;
pub const TASK_NAME_PORT: task_special_port_t = 3;
pub const TASK_BOOTSTRAP_PORT: task_special_port_t = 4;
extern "C" {
pub fn task_resume(target_task: task_t) -> kern_return_t;
pub fn task_suspend(target_task: task_t) -> kern_return_t;
pub fn task_get_special_port(task: task_t,
which_port: task_special_port_t,
special_port: *mut mach_port_t) -> kern_return_t;
pub fn task_threads(target_task: task_t,
act_list: *mut thread_act_array_t,
act_list_cnt: *mut mach_msg_type_number_t) -> kern_return_t;
pub fn task_info(
target_task: task_name_t,
flavor: task_flavor_t,
task_info_out: task_info_t,
task_info_outCnt: *mut mach_msg_type_number_t) -> kern_return_t;
pub fn task_set_info(
target_task: task_t,
flavor: task_flavor_t,
task_info_in: task_info_t,
task_info_inCnt: mach_msg_type_number_t) -> kern_return_t;
}

39
third_party/rust/mach/src/task_info.rs vendored Normal file
View File

@ -0,0 +1,39 @@
//! This module roughly corresponds to `mach/task_info.h`.
use vm_types::{integer_t, natural_t, mach_vm_address_t, mach_vm_size_t};
pub const TASK_INFO_MAX: ::std::os::raw::c_uint = 1024;
pub const TASK_BASIC_INFO_32: ::std::os::raw::c_uint = 4;
pub const TASK_BASIC2_INFO_32: ::std::os::raw::c_uint = 6;
pub const TASK_BASIC_INFO_64: ::std::os::raw::c_uint = 5;
pub const TASK_BASIC_INFO: ::std::os::raw::c_uint = 5;
pub const TASK_EVENTS_INFO: ::std::os::raw::c_uint = 2;
pub const TASK_THREAD_TIMES_INFO: ::std::os::raw::c_uint = 3;
pub const TASK_ABSOLUTETIME_INFO: ::std::os::raw::c_uint = 1;
pub const TASK_KERNELMEMORY_INFO: ::std::os::raw::c_uint = 7;
pub const TASK_SECURITY_TOKEN: ::std::os::raw::c_uint = 13;
pub const TASK_AUDIT_TOKEN: ::std::os::raw::c_uint = 15;
pub const TASK_AFFINITY_TAG_INFO: ::std::os::raw::c_uint = 16;
pub const TASK_DYLD_INFO: ::std::os::raw::c_uint = 17;
pub const TASK_DYLD_ALL_IMAGE_INFO_32: ::std::os::raw::c_uint = 0;
pub const TASK_DYLD_ALL_IMAGE_INFO_64: ::std::os::raw::c_uint = 1;
pub const TASK_EXTMOD_INFO: ::std::os::raw::c_uint = 19;
pub const MACH_TASK_BASIC_INFO: ::std::os::raw::c_uint = 20;
pub const TASK_POWER_INFO: ::std::os::raw::c_uint = 21;
pub const TASK_VM_INFO: ::std::os::raw::c_uint = 22;
pub const TASK_VM_INFO_PURGEABLE: ::std::os::raw::c_uint = 23;
pub const TASK_TRACE_MEMORY_INFO: ::std::os::raw::c_uint = 24;
pub const TASK_WAIT_STATE_INFO: ::std::os::raw::c_uint = 25;
pub const TASK_POWER_INFO_V2: ::std::os::raw::c_uint = 26;
pub const TASK_VM_INFO_PURGEABLE_ACCOUNT: ::std::os::raw::c_uint = 27;
pub const TASK_FLAGS_INFO: ::std::os::raw::c_uint = 28;
pub const TASK_DEBUG_INFO_INTERNAL: ::std::os::raw::c_uint = 29;
pub type task_flavor_t = natural_t;
pub type task_info_t = *mut integer_t;
pub struct task_dyld_info {
all_image_info_addr: mach_vm_address_t,
all_image_info_size: mach_vm_size_t,
all_image_info_format: integer_t,
}

14
third_party/rust/mach/src/thread_act.rs vendored Normal file
View File

@ -0,0 +1,14 @@
//! This module corresponds to `mach/thread_act.defs`.
use kern_return::{kern_return_t};
use message::{mach_msg_type_number_t};
use thread_status::{thread_state_t, thread_state_flavor_t};
use types::{thread_act_t};
extern "C" {
pub fn thread_get_state(target_act: thread_act_t,
flavor: thread_state_flavor_t,
new_state: thread_state_t,
new_state_count: *mut mach_msg_type_number_t)
-> kern_return_t;
}

View File

@ -0,0 +1,23 @@
//! This module corresponds to `mach/thread_status.h`.
use vm_types::{natural_t};
pub type thread_state_t = *mut natural_t;
pub type thread_state_flavor_t = ::libc::c_int;
pub static x86_THREAD_STATE32 : thread_state_flavor_t = 1;
pub static x86_FLOAT_STATE32 : thread_state_flavor_t = 2;
pub static x86_EXCEPTION_STATE32 : thread_state_flavor_t = 3;
pub static x86_THREAD_STATE64 : thread_state_flavor_t = 4;
pub static x86_FLOAT_STATE64 : thread_state_flavor_t = 5;
pub static x86_EXCEPTION_STATE64 : thread_state_flavor_t = 6;
pub static x86_THREAD_STATE : thread_state_flavor_t = 7;
pub static x86_FLOAT_STATE : thread_state_flavor_t = 8;
pub static x86_EXCEPTION_STATE : thread_state_flavor_t = 9;
pub static x86_DEBUG_STATE32 : thread_state_flavor_t = 10;
pub static x86_DEBUG_STATE64 : thread_state_flavor_t = 11;
pub static x86_DEBUG_STATE : thread_state_flavor_t = 12;
pub static THREAD_STATE_NONE : thread_state_flavor_t = 13;
pub static x86_AVX_STATE32 : thread_state_flavor_t = 16;
pub static x86_AVX_STATE64 : thread_state_flavor_t = 17;
pub static x86_AVX_STATE : thread_state_flavor_t = 18;

19
third_party/rust/mach/src/traps.rs vendored Normal file
View File

@ -0,0 +1,19 @@
//! This module corresponds to `mach/mach_traps.h`.
use kern_return::{kern_return_t};
use port::{mach_port_name_t, mach_port_t};
extern "C" {
pub fn mach_task_self() -> mach_port_t;
pub fn task_for_pid(target_tport: mach_port_name_t,
pid: ::libc::c_int,
tn: *mut mach_port_name_t) -> kern_return_t;
}
#[test]
fn mach_task_self_sanity_test() {
unsafe {
let this_task = mach_task_self();
println!("{:?}", this_task);
}
}

86
third_party/rust/mach/src/types.rs vendored Normal file
View File

@ -0,0 +1,86 @@
//! This module corresponds to `mach/mach_types.h`
use port::{mach_port_t};
pub type task_t = mach_port_t;
pub type task_name_t = mach_port_t;
pub type task_suspension_token_t = mach_port_t;
pub type thread_t = mach_port_t;
pub type thread_act_t = mach_port_t;
pub type ipc_space_t = mach_port_t;
pub type coalition_t = mach_port_t;
pub type host_t = mach_port_t;
pub type host_priv_t = mach_port_t;
pub type host_security_t = mach_port_t;
pub type processor_t = mach_port_t;
pub type processor_set_t = mach_port_t;
pub type processor_set_control_t = mach_port_t;
pub type semaphore_t = mach_port_t;
pub type lock_set_t = mach_port_t;
pub type ledger_t = mach_port_t;
pub type alarm_t = mach_port_t;
pub type clock_serv_t = mach_port_t;
pub type clock_ctrl_t = mach_port_t;
pub type processor_set_name_t = processor_set_t;
pub type clock_reply_t = mach_port_t;
pub type bootstrap_t = mach_port_t;
pub type mem_entry_name_port_t = mach_port_t;
pub type exception_handler_t = mach_port_t;
pub type exception_handler_array_t = *mut exception_handler_t;
pub type vm_task_entry_t = mach_port_t;
pub type io_master_t = mach_port_t;
pub type UNDServerRef = mach_port_t;
pub type task_array_t = *mut task_t;
pub type thread_array_t = *mut thread_t;
pub type processor_set_array_t = *mut processor_set_t;
pub type processor_set_name_array_t = *mut processor_set_t;
pub type processor_array_t = *mut processor_t;
pub type thread_act_array_t = *mut thread_act_t;
pub type ledger_array_t = *mut ledger_t;
pub type task_port_t = task_t;
pub type task_port_array_t = task_array_t;
pub type thread_port_t = thread_t;
pub type thread_port_array_t = thread_array_t;
pub type ipc_space_port_t = ipc_space_t;
pub type host_name_t = host_t;
pub type host_name_port_t = host_t;
pub type processor_set_port_t = processor_set_t;
pub type processor_set_name_port_t = processor_set_t;
pub type processor_set_name_port_array_t = processor_set_array_t;
pub type processor_set_control_port_t = processor_set_t;
pub type processor_port_t = processor_t;
pub type processor_port_array_t = processor_array_t;
pub type thread_act_port_t = thread_act_t;
pub type thread_act_port_array_t = thread_act_array_t;
pub type semaphore_port_t = semaphore_t;
pub type lock_set_port_t = lock_set_t;
pub type ledger_port_t = ledger_t;
pub type ledger_port_array_t = ledger_array_t;
pub type alarm_port_t = alarm_t;
pub type clock_serv_port_t = clock_serv_t;
pub type clock_ctrl_port_t = clock_ctrl_t;
pub type exception_port_t = exception_handler_t;
pub type exception_port_arrary_t = exception_handler_array_t;
pub const TASK_NULL: task_t = 0;
pub const TASK_NAME_NULL: task_name_t = 0;
pub const THREAD_NULL: thread_t = 0;
pub const TID_NULL: u64 = 0;
pub const THR_ACT_NULL: thread_act_t = 0;
pub const IPC_SPACE_NULL: ipc_space_t = 0;
pub const COALITION_NULL: coalition_t = 0;
pub const HOST_NULL: host_t = 0;
pub const HOST_PRIV_NULL: host_priv_t = 0;
pub const HOST_SECURITY_NULL: host_security_t = 0;
pub const PROCESSOR_SET_NULL: processor_set_t = 0;
pub const PROCESSOR_NULL: processor_t = 0;
pub const SEMAPHORE_NULL: semaphore_t = 0;
pub const LOCK_SET_NULL: lock_set_t = 0;
pub const LEDGER_NULL: ledger_t = 0;
pub const ALARM_NULL: alarm_t = 0;
pub const CLOCK_NULL: ::libc::clock_t = 0;
pub const UND_SERVER_NULL: UNDServerRef = 0;

191
third_party/rust/mach/src/vm.rs vendored Normal file
View File

@ -0,0 +1,191 @@
//! This module roughly corresponds to `mach/mach_vm.defs`.
use boolean::{boolean_t};
use kern_return::{kern_return_t};
use memory_object_types::{memory_object_offset_t, memory_object_size_t};
use message::{mach_msg_type_number_t};
use port::{mach_port_t};
use types::{mem_entry_name_port_t, vm_task_entry_t};
use vm_attributes::{vm_machine_attribute_t, vm_machine_attribute_val_t};
use vm_behavior::{vm_behavior_t};
use vm_inherit::{vm_inherit_t};
use vm_prot::{vm_prot_t};
use vm_purgable::{vm_purgable_t};
use vm_region::*;
use vm_sync::{vm_sync_t};
use vm_types::*;
extern "C" {
pub fn mach_vm_allocate(target: vm_task_entry_t,
address: *mut mach_vm_address_t,
size: mach_vm_size_t,
flags: ::libc::c_int) -> kern_return_t;
pub fn mach_vm_deallocate(target: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t) -> kern_return_t;
pub fn mach_vm_protect(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
set_maximum: boolean_t,
new_protection: vm_prot_t) -> kern_return_t;
pub fn mach_vm_inherit(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
new_inheritance: vm_inherit_t) -> kern_return_t;
pub fn mach_vm_read(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
data: *mut vm_offset_t,
dataCnt: *mut mach_msg_type_number_t) -> kern_return_t;
pub fn mach_vm_read_list(target_task: vm_task_entry_t,
data_list: mach_vm_read_entry_t,
count: natural_t) -> kern_return_t;
pub fn mach_vm_write(target_task: vm_task_entry_t,
address: mach_vm_address_t,
data: vm_offset_t,
dataCnt: mach_msg_type_number_t);
pub fn mach_vm_copy(target_task: vm_task_entry_t,
source_address: mach_vm_address_t,
size: mach_vm_size_t,
dest_address: mach_vm_address_t) -> kern_return_t;
pub fn mach_vm_read_overwrite(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
data: mach_vm_address_t,
outsize: *mut mach_vm_size_t) -> kern_return_t;
pub fn mach_vm_msync(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
sync_flags: vm_sync_t) -> kern_return_t;
pub fn mach_vm_behavior_set(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
new_behavior: vm_behavior_t) -> kern_return_t;
pub fn mach_vm_map(target_task: vm_task_entry_t,
inout: mach_vm_address_t,
size: mach_vm_size_t,
mask: mach_vm_offset_t,
flags: ::libc::c_int,
object: mem_entry_name_port_t,
offset: memory_object_offset_t,
copy: boolean_t,
cur_protection: vm_prot_t,
max_protection: vm_prot_t,
inheritance: vm_inherit_t) -> kern_return_t;
pub fn mach_vm_machine_attribute(target_task: vm_task_entry_t,
address: mach_vm_address_t,
size: mach_vm_size_t,
attribute: vm_machine_attribute_t,
value: *mut vm_machine_attribute_val_t) -> kern_return_t;
pub fn mach_vm_remap(target_task: vm_task_entry_t,
target_address: *mut mach_vm_address_t,
size: mach_vm_size_t,
mask: mach_vm_offset_t,
flags: ::libc::c_int,
src_task: vm_task_entry_t,
src_address: mach_vm_address_t,
copy: boolean_t,
cur_protection: *mut vm_prot_t,
out: *mut vm_prot_t,
inheritance: vm_inherit_t) -> kern_return_t;
pub fn mach_vm_page_query(target_map: vm_map_t,
offset: mach_vm_offset_t,
disposition: *mut integer_t,
ref_count: *mut integer_t) -> kern_return_t;
pub fn mach_vm_region_recurse(target_task: vm_task_entry_t,
address: *mut mach_vm_address_t,
size: *mut mach_vm_size_t,
nesting_depth: *mut natural_t,
info: vm_region_recurse_info_t,
infoCnt: *mut mach_msg_type_number_t) -> kern_return_t;
pub fn mach_vm_region(target_task: vm_task_entry_t,
address: *mut mach_vm_address_t,
size: *mut mach_vm_size_t,
flavor: vm_region_flavor_t,
info: vm_region_info_t,
infoCnt: *mut mach_msg_type_number_t,
object_name: *mut mach_port_t) -> kern_return_t;
pub fn mach_make_memory_entry(target_task: vm_task_entry_t,
size: *mut memory_object_size_t,
offset: memory_object_offset_t,
permission: vm_prot_t,
object_handle: *mut mem_entry_name_port_t,
parent_handle: mem_entry_name_port_t) -> kern_return_t;
pub fn mach_make_memory_entry_64(target_task: vm_map_t,
size: *mut memory_object_size_t,
offset: memory_object_offset_t,
permission: vm_prot_t,
object_handle: *mut mach_port_t,
parent_entry: mem_entry_name_port_t) -> kern_return_t;
pub fn mach_vm_purgable_control(target_task: vm_task_entry_t,
address: mach_vm_address_t,
control: vm_purgable_t,
state: *mut ::libc::c_int) -> kern_return_t;
pub fn mach_vm_page_info(target_task: vm_task_entry_t,
address: mach_vm_address_t,
flavor: vm_page_info_flavor_t,
info: vm_page_info_t,
infoCnt: *mut mach_msg_type_number_t) -> kern_return_t;
}
#[test]
fn mach_vm_allocate_sanity_test() {
use kern_return::*;
use traps::mach_task_self;
use vm_statistics::VM_FLAGS_ANYWHERE;
unsafe {
let size = 0x100;
let task = mach_task_self();
let mut address: mach_vm_address_t = 0;
assert_eq!(mach_vm_allocate(task, &mut address, size, VM_FLAGS_ANYWHERE), KERN_SUCCESS);
println!("0x{:x}", address);
assert_eq!(mach_vm_deallocate(task, address, size), KERN_SUCCESS);
}
}
#[test]
fn mach_vm_region_sanity_test() {
use kern_return::*;
use traps::mach_task_self;
use vm_prot::*;
unsafe {
let mut size = 0x10;
let mut object_name = 0;
let mut address = mach_vm_region_sanity_test as mach_vm_address_t;
let mut info: vm_region_basic_info_64 = ::std::mem::zeroed();
let mut info_size = vm_region_basic_info_64::count();
let result = mach_vm_region(mach_task_self(),
&mut address,
&mut size,
VM_REGION_BASIC_INFO_64,
(&mut info as *mut _) as vm_region_info_t,
&mut info_size,
&mut object_name);
assert_eq!(result, KERN_SUCCESS);
assert_eq!(info.protection, VM_PROT_READ | VM_PROT_EXECUTE);
}
}

View File

@ -0,0 +1,18 @@
//! This module corresponds to `mach/vm_attributes.h`.
pub type vm_machine_attribute_t = ::libc::c_uint;
pub const MATTR_CACHE: vm_machine_attribute_t = (1 << 0);
pub const MATTR_MIGRATE: vm_machine_attribute_t = (1 << 1);
pub const MATTR_REPLICATE: vm_machine_attribute_t = (1 << 2);
pub type vm_machine_attribute_val_t = ::libc::c_int;
pub const MATTR_VAL_OFF: vm_machine_attribute_val_t = 0;
pub const MATTR_VAL_ON: vm_machine_attribute_val_t = 1;
pub const MATTR_VAL_GET: vm_machine_attribute_val_t = 2;
pub const MATTR_VAL_CACHE_FLUSH: vm_machine_attribute_val_t = 6;
pub const MATTR_VAL_DCACHE_FLUSH: vm_machine_attribute_val_t = 7;
pub const MATTR_VAL_ICACHE_FLUSH: vm_machine_attribute_val_t = 8;
pub const MATTR_VAL_CACHE_SYNC: vm_machine_attribute_val_t = 9;
pub const MATTR_VAL_GET_INFO: vm_machine_attribute_val_t = 10;

View File

@ -0,0 +1,15 @@
//! This module corresponds to `mach/vm_behavior.h`.
pub type vm_behavior_t = ::libc::c_int;
pub const VM_BEHAVIOR_DEFAULT: vm_behavior_t = 0;
pub const VM_BEHAVIOR_RANDOM: vm_behavior_t = 1;
pub const VM_BEHAVIOR_SEQUENTIAL: vm_behavior_t = 2;
pub const VM_BEHAVIOR_RSEQNTL: vm_behavior_t = 3;
pub const VM_BEHAVIOR_WILLNEED: vm_behavior_t = 4;
pub const VM_BEHAVIOR_DONTNEED: vm_behavior_t = 5;
pub const VM_BEHAVIOR_FREE: vm_behavior_t = 6;
pub const VM_BEHAVIOR_ZERO_WIRED_PAGES: vm_behavior_t = 7;
pub const VM_BEHAVIOR_REUSABLE: vm_behavior_t = 8;
pub const VM_BEHAVIOR_REUSE: vm_behavior_t = 9;
pub const VM_BEHAVIOR_CAN_REUSE: vm_behavior_t = 10;

10
third_party/rust/mach/src/vm_inherit.rs vendored Normal file
View File

@ -0,0 +1,10 @@
//! This module corresponds to `mach/vm_inherit.h`.
pub type vm_inherit_t = ::libc::c_uint;
pub const VM_INHERIT_SHARE: vm_inherit_t = 0;
pub const VM_INHERIT_COPY: vm_inherit_t = 1;
pub const VM_INHERIT_NONE: vm_inherit_t = 2;
pub const VM_INHERIT_DONATE_COPY: vm_inherit_t = 3;
pub const VM_INHERIT_DEFAULT: vm_inherit_t = VM_INHERIT_COPY;
pub const VM_INHERIT_LAST_VALID: vm_inherit_t = VM_INHERIT_NONE;

View File

@ -0,0 +1,27 @@
//! This module roughly corresponds to `mach/vm_page_size.h`
use vm_types::{vm_size_t, mach_vm_size_t, mach_vm_offset_t};
extern "C" {
pub static vm_page_size: vm_size_t;
pub static vm_page_mask: vm_size_t;
pub static vm_page_shift: ::libc::c_int;
}
pub unsafe fn mach_vm_trunc_page(x: mach_vm_offset_t) -> mach_vm_offset_t {
(x & !(vm_page_mask as mach_vm_size_t))
}
pub unsafe fn mach_vm_round_page(x: mach_vm_offset_t) -> mach_vm_offset_t {
((x + vm_page_mask as mach_vm_size_t) & !(vm_page_mask as mach_vm_size_t))
}
#[test]
fn page_size_test() {
unsafe {
assert!(vm_page_size > 0);
assert!(vm_page_size % 2 == 0);
assert_eq!(mach_vm_round_page(1), vm_page_size as mach_vm_size_t);
println!("{:?}", vm_page_size);
}
}

14
third_party/rust/mach/src/vm_prot.rs vendored Normal file
View File

@ -0,0 +1,14 @@
//! This module corresponds to `mach/vm_prot.h`.
pub type vm_prot_t = ::libc::c_int;
pub const VM_PROT_NONE: vm_prot_t = 0;
pub const VM_PROT_READ: vm_prot_t = (1 << 0);
pub const VM_PROT_WRITE: vm_prot_t = (1 << 1);
pub const VM_PROT_EXECUTE: vm_prot_t = (1 << 2);
pub const VM_PROT_NO_CHANGE: vm_prot_t = (1 << 3);
pub const VM_PROT_COPY: vm_prot_t = (1 << 4);
pub const VM_PROT_WANTS_COPY: vm_prot_t = (1 << 4);
pub const VM_PROT_TRUSTED: vm_prot_t = (1 << 5);
pub const VM_PROT_DEFAULT: vm_prot_t = VM_PROT_READ | VM_PROT_WRITE;
pub const VM_PROT_ALL: vm_prot_t = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;

View File

@ -0,0 +1,42 @@
//! This module corresponds to `mach/vm_purgable.h`.
pub type vm_purgable_t = ::libc::c_int;
pub const VM_PURGABLE_SET_STATE: vm_purgable_t = 0;
pub const VM_PURGABLE_GET_STATE: vm_purgable_t = 1;
pub const VM_VOLATILE_GROUP_SHIFT: ::libc::c_int = 8;
pub const VM_VOLATILE_GROUP_MASK: ::libc::c_int = (7 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_DEFAULT: ::libc::c_int = VM_VOLATILE_GROUP_7;
pub const VM_VOLATILE_GROUP_0: ::libc::c_int = (0 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_1: ::libc::c_int = (1 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_2: ::libc::c_int = (2 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_3: ::libc::c_int = (3 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_4: ::libc::c_int = (4 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_5: ::libc::c_int = (5 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_6: ::libc::c_int = (6 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_VOLATILE_GROUP_7: ::libc::c_int = (7 << VM_VOLATILE_GROUP_SHIFT);
pub const VM_PURGABLE_BEHAVIOR_SHIFT: ::libc::c_int = 6;
pub const VM_PURGABLE_BEHAVIOR_MASK: ::libc::c_int = (1 << VM_PURGABLE_BEHAVIOR_SHIFT);
pub const VM_PURGABLE_BEHAVIOR_FIFO: ::libc::c_int = (0 << VM_PURGABLE_BEHAVIOR_SHIFT);
pub const VM_PURGABLE_BEHAVIOR_LIFO: ::libc::c_int = (1 << VM_PURGABLE_BEHAVIOR_SHIFT);
pub const VM_PURGABLE_ORDERING_SHIFT: ::libc::c_int = 5;
pub const VM_PURGABLE_ORDERING_MASK: ::libc::c_int = (1 << VM_PURGABLE_ORDERING_SHIFT);
pub const VM_PURGABLE_ORDERING_OBSOLETE: ::libc::c_int = (1 << VM_PURGABLE_ORDERING_SHIFT);
pub const VM_PURGABLE_ORDERING_NORMAL: ::libc::c_int = (0 << VM_PURGABLE_ORDERING_SHIFT);
pub const VM_VOLATILE_ORDER_SHIFT: ::libc::c_int = 4;
pub const VM_VOLATILE_ORDER_MASK: ::libc::c_int = (1 << VM_VOLATILE_ORDER_SHIFT);
pub const VM_VOLATILE_MAKE_FIRST_IN_GROUP: ::libc::c_int = (1 << VM_VOLATILE_ORDER_SHIFT);
pub const VM_VOLATILE_MAKE_LAST_IN_GROUP: ::libc::c_int = (0 << VM_VOLATILE_ORDER_SHIFT);
pub const VM_PURGABLE_STATE_MIN: ::libc::c_int = 0;
pub const VM_PURGABLE_STATE_MAX: ::libc::c_int = 3;
pub const VM_PURGABLE_STATE_MASK: ::libc::c_int = 3;
pub const VM_PURGABLE_NONVOLATILE: ::libc::c_int = 0;
pub const VM_PURGABLE_VOLATILE: ::libc::c_int = 1;
pub const VM_PURGABLE_EMPTY: ::libc::c_int = 2;
pub const VM_PURGABLE_DENY: ::libc::c_int = 3;

237
third_party/rust/mach/src/vm_region.rs vendored Normal file
View File

@ -0,0 +1,237 @@
//! This module roughly corresponds to `mach/vm_region.h`.
use std::mem;
use boolean::{boolean_t};
use memory_object_types::{memory_object_offset_t, vm_object_id_t};
use message::{mach_msg_type_number_t};
use vm_behavior::{vm_behavior_t};
use vm_inherit::{vm_inherit_t};
use vm_prot::{vm_prot_t};
use vm_types::{mach_vm_address_t, mach_vm_size_t};
pub type vm32_object_id_t = ::libc::uint32_t;
pub type vm_region_info_t = *mut ::libc::c_int;
pub type vm_region_info_64_t = *mut ::libc::c_int;
pub type vm_region_recurse_info_t = *mut ::libc::c_int;
pub type vm_region_recurse_info_64_t = *mut ::libc::c_int;
pub type vm_region_flavor_t = ::libc::c_int;
pub type vm_region_info_data_t = [::libc::c_int; VM_REGION_INFO_MAX as usize];
pub type vm_region_basic_info_64_t = *mut vm_region_basic_info_64;
pub type vm_region_basic_info_data_64_t = vm_region_basic_info_64;
pub type vm_region_basic_info_t = *mut vm_region_basic_info;
pub type vm_region_basic_info_data_t = vm_region_basic_info;
pub type vm_region_extended_info_t = *mut vm_region_extended_info;
pub type vm_region_extended_info_data_t = vm_region_extended_info;
pub type vm_region_top_info_t = *mut vm_region_top_info;
pub type vm_region_top_info_data_t = vm_region_top_info;
pub type vm_region_submap_info_t = *mut vm_region_submap_info;
pub type vm_region_submap_info_data_t = vm_region_submap_info;
pub type vm_region_submap_info_64_t = *mut vm_region_submap_info_64;
pub type vm_region_submap_info_data_64_t = vm_region_submap_info_64;
pub type vm_region_submap_short_info_64_t = *mut vm_region_submap_short_info_64;
pub type vm_region_submap_short_info_data_64_t = vm_region_submap_short_info_64;
pub type vm_page_info_t = *mut ::libc::c_int;
pub type vm_page_info_flavor_t = ::libc::c_int;
pub type vm_page_info_basic_t = *mut vm_page_info_basic;
pub type vm_page_info_basic_data_t = vm_page_info_basic;
pub type mach_vm_read_entry_t = [mach_vm_read_entry; VM_MAP_ENTRY_MAX as usize];
pub const VM_REGION_INFO_MAX: ::libc::c_int = (1 << 10);
pub const VM_MAP_ENTRY_MAX: ::libc::c_int = (1 << 8);
pub const VM_PAGE_INFO_BASIC: vm_page_info_flavor_t = 1;
pub const VM_REGION_BASIC_INFO_64: vm_region_flavor_t = 9;
pub const VM_REGION_BASIC_INFO: vm_region_flavor_t = 10;
pub const VM_REGION_EXTENDED_INFO: vm_region_flavor_t = 11;
pub const VM_REGION_TOP_INFO: vm_region_flavor_t = 12;
pub const SM_COW: ::libc::c_uchar = 1;
pub const SM_PRIVATE: ::libc::c_uchar = 2;
pub const SM_EMPTY: ::libc::c_uchar = 3;
pub const SM_SHARED: ::libc::c_uchar = 4;
pub const SM_TRUESHARED: ::libc::c_uchar = 5;
pub const SM_PRIVATE_ALIASED: ::libc::c_uchar = 6;
pub const SM_SHARED_ALIASED: ::libc::c_uchar = 7;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_basic_info_64 {
pub protection: vm_prot_t,
pub max_protection: vm_prot_t,
pub inheritance: vm_inherit_t,
pub shared: boolean_t,
pub reserved: boolean_t,
pub offset: memory_object_offset_t,
pub behavior: vm_behavior_t,
pub user_wired_count: ::libc::c_ushort,
}
impl vm_region_basic_info_64 {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_basic_info {
pub protection: vm_prot_t,
pub max_protection: vm_prot_t,
pub inheritance: vm_inherit_t,
pub shared: boolean_t,
pub reserved: boolean_t,
pub offset: ::libc::uint32_t,
pub behavior: vm_behavior_t,
pub user_wired_count: ::libc::c_ushort,
}
impl vm_region_basic_info {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_extended_info {
pub protection: vm_prot_t,
pub user_tag: ::libc::c_uint,
pub pages_resident: ::libc::c_uint,
pub pages_shared_now_private: ::libc::c_uint,
pub pages_swapped_out: ::libc::c_uint,
pub pages_dirtied: ::libc::c_uint,
pub ref_count: ::libc::c_uint,
pub shadow_depth: ::libc::c_ushort,
pub external_pager: ::libc::c_uchar,
pub share_mode: ::libc::c_uchar,
}
impl vm_region_extended_info {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_top_info {
pub obj_id: ::libc::c_uint,
pub ref_count: ::libc::c_uint,
pub private_pages_resident: ::libc::c_uint,
pub shared_pages_resident: ::libc::c_uint,
pub share_mode: ::libc::c_uchar,
}
impl vm_region_top_info {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_submap_info {
pub protection: vm_prot_t,
pub max_protection: vm_prot_t,
pub inheritance: vm_inherit_t,
pub offset: ::libc::uint32_t,
pub user_tag: ::libc::c_uint,
pub pages_resident: ::libc::c_uint,
pub pages_shared_now_private: ::libc::c_uint,
pub pages_swapped_out: ::libc::c_uint,
pub pages_dirtied: ::libc::c_uint,
pub ref_count: ::libc::c_uint,
pub shadow_depth: ::libc::c_ushort,
pub external_pager: ::libc::c_uchar,
pub share_mode: ::libc::c_uchar,
pub is_submap: boolean_t,
pub behavior: vm_behavior_t,
pub object_id: vm32_object_id_t,
pub user_wired_count: ::libc::c_ushort,
}
impl vm_region_submap_info {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_submap_info_64 {
pub protection: vm_prot_t,
pub max_protection: vm_prot_t,
pub inheritance: vm_inherit_t,
pub offset: memory_object_offset_t,
pub user_tag: ::libc::c_uint,
pub pages_resident: ::libc::c_uint,
pub pages_shared_now_private: ::libc::c_uint,
pub pages_swapped_out: ::libc::c_uint,
pub pages_dirtied: ::libc::c_uint,
pub ref_count: ::libc::c_uint,
pub shadow_depth: ::libc::c_ushort,
pub external_pager: ::libc::c_uchar,
pub share_mode: ::libc::c_uchar,
pub is_submap: boolean_t,
pub behavior: vm_behavior_t,
pub object_id: vm32_object_id_t,
pub user_wired_count: ::libc::c_ushort,
}
impl vm_region_submap_info_64 {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_region_submap_short_info_64 {
pub protection: vm_prot_t,
pub max_protection: vm_prot_t,
pub inheritance: vm_inherit_t,
pub offset: memory_object_offset_t,
pub user_tag: ::libc::c_uint,
pub ref_count: ::libc::c_uint,
pub shadow_depth: ::libc::c_ushort,
pub external_pager: ::libc::c_uchar,
pub share_mode: ::libc::c_uchar,
pub is_submap: boolean_t,
pub behavior: vm_behavior_t,
pub object_id: vm32_object_id_t,
pub user_wired_count: ::libc::c_ushort,
}
impl vm_region_submap_short_info_64 {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct vm_page_info_basic {
pub disposition: ::libc::c_int,
pub ref_count: ::libc::c_int,
pub object_id: vm_object_id_t,
pub offset: memory_object_offset_t,
pub depth: ::libc::c_int,
pub __pad: ::libc::c_int,
}
impl vm_page_info_basic {
pub fn count() -> mach_msg_type_number_t {
(mem::size_of::<Self>() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct mach_vm_read_entry {
pub address: mach_vm_address_t,
pub size: mach_vm_size_t,
}

View File

@ -0,0 +1,58 @@
//! This module roughly corresponds to `mach/vm_statistics.h`
use vm_types::integer_t;
pub type vm_statistics_t = *mut vm_statistics;
pub type vm_statistics_data_t = vm_statistics;
pub type pmap_statistics_t = *mut pmap_statistics;
pub const VM_PAGE_QUERY_PAGE_PRESENT: integer_t = (1 << 0);
pub const VM_PAGE_QUERY_PAGE_FICTITIOUS: integer_t = (1 << 1);
pub const VM_PAGE_QUERY_PAGE_REF: integer_t = (1 << 2);
pub const VM_PAGE_QUERY_PAGE_DIRTY: integer_t = (1 << 3);
pub const VM_MEMORY_MALLOC: ::libc::c_uint = 1;
pub const VM_MEMORY_MALLOC_SMALL: ::libc::c_uint = 2;
pub const VM_MEMORY_MALLOC_LARGE: ::libc::c_uint = 3;
pub const VM_MEMORY_MALLOC_HUGE: ::libc::c_uint = 4;
pub const VM_MEMORY_SBRK: ::libc::c_uint = 5;
pub const VM_MEMORY_ANALYSIS_TOOL: ::libc::c_uint = 10;
pub const VM_MEMORY_MACH_MSG: ::libc::c_uint = 20;
pub const VM_MEMORY_IOKIT: ::libc::c_uint = 21;
pub const VM_MEMORY_STACK: ::libc::c_uint = 30;
pub const VM_MEMORY_GUARD: ::libc::c_uint = 31;
pub const VM_MEMORY_SHARED_PMAP: ::libc::c_uint = 32;
pub const VM_MEMORY_DYLIB: ::libc::c_uint = 33;
pub const VM_MEMORY_APPKIT: ::libc::c_uint = 40;
pub const VM_MEMORY_FOUNDATION: ::libc::c_uint = 41;
pub const VM_MEMORY_COREGRAPHICS: ::libc::c_uint = 42;
pub const VM_MEMORY_CARBON: ::libc::c_uint = 43;
pub const VM_MEMORY_JAVA: ::libc::c_uint = 44;
pub const VM_MEMORY_ATS: ::libc::c_uint = 50;
pub const VM_MEMORY_DYLD: ::libc::c_uint = 60;
pub const VM_MEMORY_DYLD_MALLOC: ::libc::c_uint = 61;
pub const VM_MEMORY_APPLICATION_SPECIFIC_1: ::libc::c_uint = 240;
pub const VM_MEMORY_APPLICATION_SPECIFIC_16: ::libc::c_uint = 255;
pub const VM_FLAGS_FIXED: ::libc::c_int = 0x0;
pub const VM_FLAGS_ANYWHERE: ::libc::c_int = 0x1;
pub struct vm_statistics {
pub free_count: integer_t,
pub active_count: integer_t,
pub inactive_count: integer_t,
pub wire_count: integer_t,
pub zero_fill_count: integer_t,
pub reactivations: integer_t,
pub pageins: integer_t,
pub pageouts: integer_t,
pub faults: integer_t,
pub cow_faults: integer_t,
pub lookups: integer_t,
pub hits: integer_t,
}
pub struct pmap_statistics {
pub resident_count: integer_t,
pub wired_count: integer_t,
}

11
third_party/rust/mach/src/vm_sync.rs vendored Normal file
View File

@ -0,0 +1,11 @@
//! This module corresponds to `mach/vm_sync.h`.
pub type vm_sync_t = ::libc::c_uint;
pub const VM_SYNC_ASYNCHRONOUS: vm_sync_t = (1 << 0);
pub const VM_SYNC_SYNCHRONOUS: vm_sync_t = (1 << 1);
pub const VM_SYNC_INVALIDATE: vm_sync_t = (1 << 2);
pub const VM_SYNC_KILLPAGES: vm_sync_t = (1 << 3);
pub const VM_SYNC_DEACTIVATE: vm_sync_t = (1 << 4);
pub const VM_SYNC_CONTIGUOUS: vm_sync_t = (1 << 5);
pub const VM_SYNC_REUSABLEPAGES: vm_sync_t = (1 << 6);

19
third_party/rust/mach/src/vm_types.rs vendored Normal file
View File

@ -0,0 +1,19 @@
//! This module roughly corresponds to `mach/i386/vm_types.h`.
pub type natural_t = ::libc::c_uint;
pub type integer_t = ::libc::c_int;
pub type user_addr_t = usize;
pub type mach_vm_address_t = u64;
pub type mach_vm_offset_t = u64;
pub type mach_vm_size_t = u64;
pub type vm_map_offset_t = u64;
pub type vm_map_address_t = u64;
pub type vm_map_size_t = u64;
pub type vm_map_t = ::port::mach_port_t;
pub type vm_offset_t = ::libc::uintptr_t;
pub type vm_size_t = ::libc::uintptr_t;
pub type vm_address_t = vm_offset_t;
pub type mach_port_context_t = mach_vm_address_t;