mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
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:
parent
be02258965
commit
6af26dcc3d
45
Cargo.lock
generated
45
Cargo.lock
generated
@ -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"
|
||||
|
1
third_party/rust/audio_thread_priority/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/audio_thread_priority/.cargo-checksum.json
vendored
Normal 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"}
|
48
third_party/rust/audio_thread_priority/Cargo.toml
vendored
Normal file
48
third_party/rust/audio_thread_priority/Cargo.toml
vendored
Normal 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"]
|
5
third_party/rust/audio_thread_priority/Makefile
vendored
Normal file
5
third_party/rust/audio_thread_priority/Makefile
vendored
Normal 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
|
37
third_party/rust/audio_thread_priority/README.md
vendored
Normal file
37
third_party/rust/audio_thread_priority/README.md
vendored
Normal 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
|
||||
|
56
third_party/rust/audio_thread_priority/audio_thread_priority.h
vendored
Normal file
56
third_party/rust/audio_thread_priority/audio_thread_priority.h
vendored
Normal 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
|
3
third_party/rust/audio_thread_priority/generate_osx_bindings.sh
vendored
Normal file
3
third_party/rust/audio_thread_priority/generate_osx_bindings.sh
vendored
Normal 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
|
209
third_party/rust/audio_thread_priority/src/lib.rs
vendored
Normal file
209
third_party/rust/audio_thread_priority/src/lib.rs
vendored
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
36
third_party/rust/audio_thread_priority/src/mach_sys.rs
vendored
Normal file
36
third_party/rust/audio_thread_priority/src/mach_sys.rs
vendored
Normal 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;
|
132
third_party/rust/audio_thread_priority/src/rt_linux.rs
vendored
Normal file
132
third_party/rust/audio_thread_priority/src/rt_linux.rs
vendored
Normal 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(());
|
||||
}
|
||||
|
149
third_party/rust/audio_thread_priority/src/rt_mach.rs
vendored
Normal file
149
third_party/rust/audio_thread_priority/src/rt_mach.rs
vendored
Normal 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)
|
||||
}
|
57
third_party/rust/audio_thread_priority/src/rt_win.rs
vendored
Normal file
57
third_party/rust/audio_thread_priority/src/rt_win.rs
vendored
Normal 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)
|
||||
}
|
1
third_party/rust/dbus/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/dbus/.cargo-checksum.json
vendored
Normal 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
38
third_party/rust/dbus/Cargo.toml
vendored
Normal 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
202
third_party/rust/dbus/LICENSE-APACHE
vendored
Normal 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
19
third_party/rust/dbus/LICENSE-MIT
vendored
Normal 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.
|
177
third_party/rust/dbus/examples/adv_server.rs
vendored
Normal file
177
third_party/rust/dbus/examples/adv_server.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
193
third_party/rust/dbus/examples/argument_guide.md
vendored
Normal file
193
third_party/rust/dbus/examples/argument_guide.md
vendored
Normal 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.
|
||||
|
||||
|
14
third_party/rust/dbus/examples/client.rs
vendored
Normal file
14
third_party/rust/dbus/examples/client.rs
vendored
Normal 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); }
|
||||
}
|
||||
|
50
third_party/rust/dbus/examples/properties.rs
vendored
Normal file
50
third_party/rust/dbus/examples/properties.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
10
third_party/rust/dbus/examples/properties_msgitem.rs
vendored
Normal file
10
third_party/rust/dbus/examples/properties_msgitem.rs
vendored
Normal 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
91
third_party/rust/dbus/examples/rtkit.rs
vendored
Normal 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),
|
||||
}
|
||||
}
|
72
third_party/rust/dbus/examples/server.rs
vendored
Normal file
72
third_party/rust/dbus/examples/server.rs
vendored
Normal 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(); }
|
||||
}
|
25
third_party/rust/dbus/examples/unity_focused_window.rs
vendored
Normal file
25
third_party/rust/dbus/examples/unity_focused_window.rs
vendored
Normal 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) };
|
||||
}
|
||||
}
|
||||
|
483
third_party/rust/dbus/src/arg/array_impl.rs
vendored
Normal file
483
third_party/rust/dbus/src/arg/array_impl.rs
vendored
Normal 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
|
||||
}
|
||||
|
||||
|
308
third_party/rust/dbus/src/arg/basic_impl.rs
vendored
Normal file
308
third_party/rust/dbus/src/arg/basic_impl.rs
vendored
Normal 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
440
third_party/rust/dbus/src/arg/mod.rs
vendored
Normal 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
336
third_party/rust/dbus/src/arg/msgarg.rs
vendored
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
242
third_party/rust/dbus/src/arg/variantstruct_impl.rs
vendored
Normal file
242
third_party/rust/dbus/src/arg/variantstruct_impl.rs
vendored
Normal 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
733
third_party/rust/dbus/src/connection.rs
vendored
Normal 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
281
third_party/rust/dbus/src/lib.rs
vendored
Normal 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
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
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
553
third_party/rust/dbus/src/objpath.rs
vendored
Normal 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
136
third_party/rust/dbus/src/prop.rs
vendored
Normal 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
96
third_party/rust/dbus/src/signalargs.rs
vendored
Normal 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
212
third_party/rust/dbus/src/stdintf.rs
vendored
Normal 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
210
third_party/rust/dbus/src/strings.rs
vendored
Normal 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)");
|
||||
}
|
137
third_party/rust/dbus/src/tree/factory.rs
vendored
Normal file
137
third_party/rust/dbus/src/tree/factory.rs
vendored
Normal 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
653
third_party/rust/dbus/src/tree/leaves.rs
vendored
Normal 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);
|
||||
}
|
275
third_party/rust/dbus/src/tree/methodtype.rs
vendored
Normal file
275
third_party/rust/dbus/src/tree/methodtype.rs
vendored
Normal 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
35
third_party/rust/dbus/src/tree/mod.rs
vendored
Normal 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;
|
536
third_party/rust/dbus/src/tree/objectpath.rs
vendored
Normal file
536
third_party/rust/dbus/src/tree/objectpath.rs
vendored
Normal 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
100
third_party/rust/dbus/src/tree/utils.rs
vendored
Normal 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
242
third_party/rust/dbus/src/watch.rs
vendored
Normal 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!() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
third_party/rust/libdbus-sys/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/libdbus-sys/.cargo-checksum.json
vendored
Normal 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
28
third_party/rust/libdbus-sys/Cargo.toml
vendored
Normal 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"
|
202
third_party/rust/libdbus-sys/LICENSE-APACHE
vendored
Normal file
202
third_party/rust/libdbus-sys/LICENSE-APACHE
vendored
Normal 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/libdbus-sys/LICENSE-MIT
vendored
Normal file
19
third_party/rust/libdbus-sys/LICENSE-MIT
vendored
Normal 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
7
third_party/rust/libdbus-sys/build.rs
vendored
Normal 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
300
third_party/rust/libdbus-sys/src/lib.rs
vendored
Normal 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;
|
||||
}
|
1
third_party/rust/mach/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/mach/.cargo-checksum.json
vendored
Normal 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
22
third_party/rust/mach/Cargo.toml
vendored
Normal 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
23
third_party/rust/mach/LICENSE.md
vendored
Normal 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
3
third_party/rust/mach/README.md
vendored
Normal 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.
|
129
third_party/rust/mach/examples/dump_process_registers.rs
vendored
Normal file
129
third_party/rust/mach/examples/dump_process_registers.rs
vendored
Normal 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
7
third_party/rust/mach/src/boolean.rs
vendored
Normal 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
14
third_party/rust/mach/src/bootstrap.rs
vendored
Normal 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;
|
||||
}
|
15
third_party/rust/mach/src/clock_types.rs
vendored
Normal file
15
third_party/rust/mach/src/clock_types.rs
vendored
Normal 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;
|
58
third_party/rust/mach/src/kern_return.rs
vendored
Normal file
58
third_party/rust/mach/src/kern_return.rs
vendored
Normal 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
32
third_party/rust/mach/src/lib.rs
vendored
Normal 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
22
third_party/rust/mach/src/mach_port.rs
vendored
Normal 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;
|
||||
}
|
3
third_party/rust/mach/src/mach_types.rs
vendored
Normal file
3
third_party/rust/mach/src/mach_types.rs
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
use port::mach_port_t;
|
||||
|
||||
pub type task_name_t = mach_port_t;
|
9
third_party/rust/mach/src/memory_object_types.rs
vendored
Normal file
9
third_party/rust/mach/src/memory_object_types.rs
vendored
Normal 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
248
third_party/rust/mach/src/message.rs
vendored
Normal 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
24
third_party/rust/mach/src/port.rs
vendored
Normal 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
65
third_party/rust/mach/src/structs.rs
vendored
Normal 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
36
third_party/rust/mach/src/task.rs
vendored
Normal 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
39
third_party/rust/mach/src/task_info.rs
vendored
Normal 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
14
third_party/rust/mach/src/thread_act.rs
vendored
Normal 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;
|
||||
}
|
23
third_party/rust/mach/src/thread_status.rs
vendored
Normal file
23
third_party/rust/mach/src/thread_status.rs
vendored
Normal 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
19
third_party/rust/mach/src/traps.rs
vendored
Normal 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
86
third_party/rust/mach/src/types.rs
vendored
Normal 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
191
third_party/rust/mach/src/vm.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
18
third_party/rust/mach/src/vm_attributes.rs
vendored
Normal file
18
third_party/rust/mach/src/vm_attributes.rs
vendored
Normal 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;
|
15
third_party/rust/mach/src/vm_behavior.rs
vendored
Normal file
15
third_party/rust/mach/src/vm_behavior.rs
vendored
Normal 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
10
third_party/rust/mach/src/vm_inherit.rs
vendored
Normal 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;
|
27
third_party/rust/mach/src/vm_page_size.rs
vendored
Normal file
27
third_party/rust/mach/src/vm_page_size.rs
vendored
Normal 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
14
third_party/rust/mach/src/vm_prot.rs
vendored
Normal 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;
|
42
third_party/rust/mach/src/vm_purgable.rs
vendored
Normal file
42
third_party/rust/mach/src/vm_purgable.rs
vendored
Normal 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
237
third_party/rust/mach/src/vm_region.rs
vendored
Normal 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,
|
||||
}
|
||||
|
58
third_party/rust/mach/src/vm_statistics.rs
vendored
Normal file
58
third_party/rust/mach/src/vm_statistics.rs
vendored
Normal 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
11
third_party/rust/mach/src/vm_sync.rs
vendored
Normal 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
19
third_party/rust/mach/src/vm_types.rs
vendored
Normal 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;
|
Loading…
Reference in New Issue
Block a user