summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/dbus
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/dbus')
-rw-r--r--third_party/rust/dbus/.cargo-checksum.json1
-rw-r--r--third_party/rust/dbus/Cargo.toml38
-rw-r--r--third_party/rust/dbus/LICENSE-APACHE202
-rw-r--r--third_party/rust/dbus/LICENSE-MIT19
-rw-r--r--third_party/rust/dbus/examples/adv_server.rs177
-rw-r--r--third_party/rust/dbus/examples/argument_guide.md193
-rw-r--r--third_party/rust/dbus/examples/client.rs14
-rw-r--r--third_party/rust/dbus/examples/properties.rs50
-rw-r--r--third_party/rust/dbus/examples/properties_msgitem.rs10
-rw-r--r--third_party/rust/dbus/examples/rtkit.rs67
-rw-r--r--third_party/rust/dbus/examples/server.rs72
-rw-r--r--third_party/rust/dbus/examples/unity_focused_window.rs25
-rw-r--r--third_party/rust/dbus/src/arg/array_impl.rs483
-rw-r--r--third_party/rust/dbus/src/arg/basic_impl.rs308
-rw-r--r--third_party/rust/dbus/src/arg/mod.rs440
-rw-r--r--third_party/rust/dbus/src/arg/msgarg.rs426
-rw-r--r--third_party/rust/dbus/src/arg/variantstruct_impl.rs242
-rw-r--r--third_party/rust/dbus/src/connection.rs733
-rw-r--r--third_party/rust/dbus/src/connection2.rs214
-rw-r--r--third_party/rust/dbus/src/crossroads/crossroads.rs245
-rw-r--r--third_party/rust/dbus/src/crossroads/handlers.rs138
-rw-r--r--third_party/rust/dbus/src/crossroads/info.rs220
-rw-r--r--third_party/rust/dbus/src/crossroads/mod.rs15
-rw-r--r--third_party/rust/dbus/src/crossroads/stdimpl.rs53
-rw-r--r--third_party/rust/dbus/src/dispatcher.rs129
-rw-r--r--third_party/rust/dbus/src/lib.rs284
-rw-r--r--third_party/rust/dbus/src/matchrule.rs77
-rw-r--r--third_party/rust/dbus/src/message.rs1152
-rw-r--r--third_party/rust/dbus/src/methoddisp.rs1058
-rw-r--r--third_party/rust/dbus/src/objpath.rs553
-rw-r--r--third_party/rust/dbus/src/prop.rs136
-rw-r--r--third_party/rust/dbus/src/signalargs.rs107
-rw-r--r--third_party/rust/dbus/src/stdintf.rs212
-rw-r--r--third_party/rust/dbus/src/strings.rs216
-rw-r--r--third_party/rust/dbus/src/tree/factory.rs137
-rw-r--r--third_party/rust/dbus/src/tree/leaves.rs653
-rw-r--r--third_party/rust/dbus/src/tree/methodtype.rs275
-rw-r--r--third_party/rust/dbus/src/tree/mod.rs35
-rw-r--r--third_party/rust/dbus/src/tree/objectpath.rs553
-rw-r--r--third_party/rust/dbus/src/tree/utils.rs100
-rw-r--r--third_party/rust/dbus/src/watch.rs255
41 files changed, 10317 insertions, 0 deletions
diff --git a/third_party/rust/dbus/.cargo-checksum.json b/third_party/rust/dbus/.cargo-checksum.json
new file mode 100644
index 0000000000..ededf20e3b
--- /dev/null
+++ b/third_party/rust/dbus/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"ff5bac5ffe795109feabd656a03c823b02fcad9186f6e6a957c2fb7201cd1bd8","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":"20b46aecac84aa90f0daa423dd9e2c118f1195ac777732bc4cedf9a0d85c4861","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":"63274e49ed6f6dd632349e336504e0508d191f35403a7eec2ea20fee7e4ed4a2","src/arg/msgarg.rs":"1df0674603ef7d3e6d3fc1674aa7ffe6a048c3631ea76b533757b9daed958a7b","src/arg/variantstruct_impl.rs":"d9ddc73c44f1e57b67a7a73e8204f6915b51365cd47b1caf68573eb802b93a01","src/connection.rs":"8178688223b392ba5c29bb66b7e89ab642a129da7c777e34014ff9fb6a0daae8","src/connection2.rs":"ef0ba9ace17c8465bf25f3b8d97666e4ab1a6db048653cde408f946206592dcf","src/crossroads/crossroads.rs":"a1f17a5359bb38a54c89553f08c41b2268265fcd195f757c8f409c4ea1b43272","src/crossroads/handlers.rs":"21fbc36bb79aeeb02ac05b11f02ababd544b019d3ec258d73894344fc742c58a","src/crossroads/info.rs":"88a1648d367d0b8a4870bf2fc276c576ad60a23976e2f67f6d784f2dc0c3bc28","src/crossroads/mod.rs":"3e7e03ace37f0a18422d4a724b9db166c114216b2e6d1991ca9453380aa42dff","src/crossroads/stdimpl.rs":"1ded85e9efa18e55d3e65a8cc253b0544869093723157a99b8f7bdd7c3d3149f","src/dispatcher.rs":"b98c29a2063d6e9b263854256487dedf644d3fdb9071623f1e30e7132abedc7a","src/lib.rs":"2fad04e6f162e8121a72c0bad95b77ceabf4bc1c4a86c648602a929983272dc4","src/matchrule.rs":"502fc71bfb5c8bec2b3f0b92d95679513e656b0aa89094164223042fac26435b","src/message.rs":"d07db0c6208f5057961e904e5da8aa12352d0a1d1917c07d0ab0d18a981637aa","src/methoddisp.rs":"57d5b0e7eef7b76393dfd80e2e5125b266521f3252edbc402b893f12791b933e","src/objpath.rs":"e9f662d6cc81ea0717553787773261e7fb3221b36fab1799fb281f21de961b72","src/prop.rs":"60541e569ff06f503d889a7b62dd0aa980d39be60cde01f917503a80e0b7b27f","src/signalargs.rs":"7f0a380d51788208d153e2b51a1759d43a9e4bc41b38b3268a31cd9d681b0cce","src/stdintf.rs":"29027f8cffde7354fc432b306a3ade149bc12440f08fe86d1a72074d514d7101","src/strings.rs":"49635568c8e7f5993e67bfc72941f4ef9407671c63d57c37489620386fbed724","src/tree/factory.rs":"77bfdfa9074e653b43e9c51b3e0b2dcfc9bc02948b7f9eb8e2fc0fe1a9009d14","src/tree/leaves.rs":"9c8b07925c07424a3977b8effa154e63d32addcbab1f59331025039592705bc1","src/tree/methodtype.rs":"6e77276ad1ca4040cd4bea320f525e49165e1d21df89281de4d9b1913129e0e2","src/tree/mod.rs":"471ff6e4bbd9c360326ed92867744b78235d769ba4483e0a8c20137153ab1e82","src/tree/objectpath.rs":"727fa86029f3ebd1d5de183e8f105deb1b3a273f1f89d0e02a5b227c6b1ff515","src/tree/utils.rs":"d15e64ed288ffa7477c2c35532d7f61feafb50ef6068606014101622bcd36caa","src/watch.rs":"9f323ea92206c77e184169e4b7f2a01f2014bf761d3aa5228431109283a1a4fe"},"package":"48b5f0f36f1eebe901b0e6bee369a77ed3396334bf3f09abd46454a576f71819"} \ No newline at end of file
diff --git a/third_party/rust/dbus/Cargo.toml b/third_party/rust/dbus/Cargo.toml
new file mode 100644
index 0000000000..e1d7e7c49e
--- /dev/null
+++ b/third_party/rust/dbus/Cargo.toml
@@ -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.5"
+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.2"
+[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"
diff --git a/third_party/rust/dbus/LICENSE-APACHE b/third_party/rust/dbus/LICENSE-APACHE
new file mode 100644
index 0000000000..6003c7dd9a
--- /dev/null
+++ b/third_party/rust/dbus/LICENSE-APACHE
@@ -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.
+
diff --git a/third_party/rust/dbus/LICENSE-MIT b/third_party/rust/dbus/LICENSE-MIT
new file mode 100644
index 0000000000..aec16d2daa
--- /dev/null
+++ b/third_party/rust/dbus/LICENSE-MIT
@@ -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. \ No newline at end of file
diff --git a/third_party/rust/dbus/examples/adv_server.rs b/third_party/rust/dbus/examples/adv_server.rs
new file mode 100644
index 0000000000..a71fc39a6a
--- /dev/null
+++ b/third_party/rust/dbus/examples/adv_server.rs
@@ -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);
+ }
+}
diff --git a/third_party/rust/dbus/examples/argument_guide.md b/third_party/rust/dbus/examples/argument_guide.md
new file mode 100644
index 0000000000..b36f2e937a
--- /dev/null
+++ b/third_party/rust/dbus/examples/argument_guide.md
@@ -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.
+
+
diff --git a/third_party/rust/dbus/examples/client.rs b/third_party/rust/dbus/examples/client.rs
new file mode 100644
index 0000000000..a8707013ed
--- /dev/null
+++ b/third_party/rust/dbus/examples/client.rs
@@ -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); }
+}
+
diff --git a/third_party/rust/dbus/examples/properties.rs b/third_party/rust/dbus/examples/properties.rs
new file mode 100644
index 0000000000..a410fc2ec1
--- /dev/null
+++ b/third_party/rust/dbus/examples/properties.rs
@@ -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);
+ }
+}
diff --git a/third_party/rust/dbus/examples/properties_msgitem.rs b/third_party/rust/dbus/examples/properties_msgitem.rs
new file mode 100644
index 0000000000..86e1aa5086
--- /dev/null
+++ b/third_party/rust/dbus/examples/properties_msgitem.rs
@@ -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())
+}
diff --git a/third_party/rust/dbus/examples/rtkit.rs b/third_party/rust/dbus/examples/rtkit.rs
new file mode 100644
index 0000000000..2717d417b9
--- /dev/null
+++ b/third_party/rust/dbus/examples/rtkit.rs
@@ -0,0 +1,67 @@
+/* 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 dbus::{Connection, BusType, Props, MessageItem, Message};
+
+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("RTTimeUSecMax")))) as u64;
+ let new_limit = libc::rlimit64 { rlim_cur: max_rttime, rlim_max: max_rttime };
+ 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 thread_id = unsafe { libc::syscall(libc::SYS_gettid) };
+ let r = rtkit_set_realtime(&c, thread_id as u64, prio);
+
+ if r.is_err() {
+ unsafe { libc::setrlimit64(libc::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),
+ }
+}
diff --git a/third_party/rust/dbus/examples/server.rs b/third_party/rust/dbus/examples/server.rs
new file mode 100644
index 0000000000..105593fccc
--- /dev/null
+++ b/third_party/rust/dbus/examples/server.rs
@@ -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(); }
+}
diff --git a/third_party/rust/dbus/examples/unity_focused_window.rs b/third_party/rust/dbus/examples/unity_focused_window.rs
new file mode 100644
index 0000000000..a0e07d0372
--- /dev/null
+++ b/third_party/rust/dbus/examples/unity_focused_window.rs
@@ -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) };
+ }
+}
+
diff --git a/third_party/rust/dbus/src/arg/array_impl.rs b/third_party/rust/dbus/src/arg/array_impl.rs
new file mode 100644
index 0000000000..8bccf347a4
--- /dev/null
+++ b/third_party/rust/dbus/src/arg/array_impl.rs
@@ -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
+}
+
+
diff --git a/third_party/rust/dbus/src/arg/basic_impl.rs b/third_party/rust/dbus/src/arg/basic_impl.rs
new file mode 100644
index 0000000000..66d2a0ee74
--- /dev/null
+++ b/third_party/rust/dbus/src/arg/basic_impl.rs
@@ -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");
+
diff --git a/third_party/rust/dbus/src/arg/mod.rs b/third_party/rust/dbus/src/arg/mod.rs
new file mode 100644
index 0000000000..737960b4b8
--- /dev/null
+++ b/third_party/rust/dbus/src/arg/mod.rs
@@ -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, AppendAll, ReadAll, 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, 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(m.ptr(), &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(m.ptr(), &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 give an error if successful.
+ ///
+ /// # 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: iter.read()?,
+ /// protocol: iter.read()?,
+ /// name: iter.read()?,
+ /// item_type: iter.read()?,
+ /// domain: iter.read()?,
+ /// flags: 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)));
+}
+
diff --git a/third_party/rust/dbus/src/arg/msgarg.rs b/third_party/rust/dbus/src/arg/msgarg.rs
new file mode 100644
index 0000000000..3309c35e65
--- /dev/null
+++ b/third_party/rust/dbus/src/arg/msgarg.rs
@@ -0,0 +1,426 @@
+#![allow(dead_code)]
+
+use {Signature, Message, arg::TypeMismatchError};
+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);
+}
+
+/// Helper trait to append many arguments to a message.
+pub trait AppendAll: 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>;
+}
+
+/// Helper trait to read all arguments from a message.
+pub trait ReadAll: Sized {
+ /// Performs the read operation.
+ fn read(i: &mut Iter) -> Result<Self, TypeMismatchError>;
+}
+
+
+/// 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());
+
+/// Internal trait to help generics. Implemented for (), (A1), (A1, A2) and so on (where A1: Arg, A2: Arg etc).
+///
+/// You would probably not use this trait directly, instead use generic functions which
+/// take ArgBuilder as an argument. It helps reading and appending multiple arguments
+/// to/from a message in one go.
+pub trait ArgBuilder: Sized {
+ /// A tuple of &static str. Used for introspection.
+ type strs;
+ /// Low-level introspection helper method.
+ fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(a: Self::strs, f: F);
+ /// Low-level method to read arguments from a message.
+ fn read(msg: &Message) -> Result<Self, TypeMismatchError>;
+ /// Low-level method to append arguments to a message.
+ fn append(self, msg: &mut Message);
+}
+
+impl ArgBuilder for () {
+ type strs = ();
+ fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(_: Self::strs, _: F) {}
+ fn read(_: &Message) -> Result<Self, TypeMismatchError> { Ok(()) }
+ fn append(self, _: &mut Message) {}
+}
+
+macro_rules! argbuilder_impl {
+ ($($n: ident $t: ident $s: ty,)+) => {
+
+impl<$($t: Arg + Append + for<'z> Get<'z>),*> ArgBuilder for ($($t,)*) {
+ type strs = ($(&'static $s,)*);
+ fn strs_sig<Q: FnMut(&'static str, Signature<'static>)>(z: Self::strs, mut q: Q) {
+ let ( $($n,)*) = z;
+ $( q($n, $t::signature()); )*
+ }
+
+ fn read(msg: &Message) -> Result<Self, TypeMismatchError> {
+ let mut ii = msg.iter_init();
+ $( let $n = ii.read()?; )*
+ Ok(($( $n, )* ))
+ }
+
+ fn append(self, msg: &mut Message) {
+ let ( $($n,)*) = self;
+ let mut ia = IterAppend::new(msg);
+ $( ia.append($n); )*
+ }
+}
+
+impl<$($t: Append),*> AppendAll for ($($t,)*) {
+ fn append(self, ia: &mut IterAppend) {
+ let ( $($n,)*) = self;
+ $( ia.append($n); )*
+ }
+}
+
+impl<$($t: Arg + for<'z> Get<'z>),*> ReadAll for ($($t,)*) {
+ fn read(ii: &mut Iter) -> Result<Self, TypeMismatchError> {
+ $( let $n = ii.read()?; )*
+ Ok(($( $n, )* ))
+ }
+}
+
+
+ }
+}
+
+argbuilder_impl!(a A str,);
+argbuilder_impl!(a A str, b B str,);
+argbuilder_impl!(a A str, b B str, c C str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str,);
+argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str,);
+
+
+
+#[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),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/dbus/src/arg/variantstruct_impl.rs b/third_party/rust/dbus/src/arg/variantstruct_impl.rs
new file mode 100644
index 0000000000..d58c99e098
--- /dev/null
+++ b/third_party/rust/dbus/src/arg/variantstruct_impl.rs
@@ -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()) }
+}
+
diff --git a/third_party/rust/dbus/src/connection.rs b/third_party/rust/dbus/src/connection.rs
new file mode 100644
index 0000000000..18b8374da8
--- /dev/null
+++ b/third_party/rust/dbus/src/connection.rs
@@ -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 = 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()) == 0 } {
+ 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()) != 0 }
+ }
+
+ /// 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(), msg.ptr(),
+ timeout_ms as c_int, e.get_mut())
+ };
+ if response == ptr::null_mut() {
+ return Err(e);
+ }
+ Ok(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(), msg.ptr(), &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);
+}
+
diff --git a/third_party/rust/dbus/src/connection2.rs b/third_party/rust/dbus/src/connection2.rs
new file mode 100644
index 0000000000..e318e921ee
--- /dev/null
+++ b/third_party/rust/dbus/src/connection2.rs
@@ -0,0 +1,214 @@
+use crate::{BusType, Error, Message, to_c_str, Watch};
+use std::{ptr, str};
+use std::ffi::CStr;
+use std::os::raw::{c_void};
+
+#[derive(Debug)]
+pub struct ConnHandle(*mut ffi::DBusConnection);
+
+unsafe impl Send for ConnHandle {}
+unsafe impl Sync for ConnHandle {}
+
+impl Drop for ConnHandle {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::dbus_connection_close(self.0);
+ ffi::dbus_connection_unref(self.0);
+ }
+ }
+}
+
+/// Experimental rewrite of Connection [unstable / experimental]
+///
+/// Slightly lower level, with better support for async operations.
+/// Also, this struct is Send + Sync.
+///
+/// Blocking operations should be clearly marked as such, although if you
+/// try to access the connection from several threads at the same time,
+/// blocking might occur due to an internal mutex inside the dbus library.
+///
+/// This version avoids dbus_connection_dispatch, and thus avoids
+/// callbacks from that function. Instead the same functionality needs to be
+/// implemented by these bindings somehow - this is not done yet.
+#[derive(Debug)]
+pub struct TxRx {
+ handle: ConnHandle,
+}
+
+impl TxRx {
+ #[inline(always)]
+ pub (crate) fn conn(&self) -> *mut ffi::DBusConnection {
+ self.handle.0
+ }
+
+ fn conn_from_ptr(ptr: *mut ffi::DBusConnection) -> Result<TxRx, Error> {
+ let handle = ConnHandle(ptr);
+
+ /* No, we don't want our app to suddenly quit if dbus goes down */
+ unsafe { ffi::dbus_connection_set_exit_on_disconnect(ptr, 0) };
+
+ let c = TxRx { handle };
+
+ Ok(c)
+ }
+
+
+ /// Creates a new D-Bus connection.
+ ///
+ /// Blocking: until the connection is up and running.
+ pub fn get_private(bus: BusType) -> Result<TxRx, 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.
+ ///
+ /// Blocking: until the connection is established.
+ pub fn open_private(address: &str) -> Result<TxRx, 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`
+ ///
+ /// Blocking: until a "Hello" response is received from the server.
+ pub fn register(&mut self) -> Result<(), Error> {
+ // This function needs to take &mut self, because it changes unique_name and unique_name takes a &self
+ let mut e = Error::empty();
+ if unsafe { ffi::dbus_bus_register(self.conn(), e.get_mut()) == 0 } {
+ 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()) != 0 }
+ }
+
+ /// Get the connection's unique name.
+ ///
+ /// It's usually something like ":1.54"
+ pub fn unique_name(&self) -> Option<&str> {
+ let c = unsafe { ffi::dbus_bus_get_unique_name(self.conn()) };
+ if c == ptr::null_mut() { return None; }
+ let s = unsafe { CStr::from_ptr(c) };
+ str::from_utf8(s.to_bytes()).ok()
+ }
+
+
+ /// Puts a message into libdbus out queue. Use "flush" or "read_write" to make sure it is sent over the wire.
+ ///
+ /// Returns a serial number than can be used to match against a reply.
+ pub fn send(&self, msg: Message) -> Result<u32, ()> {
+ let mut serial = 0u32;
+ let r = unsafe { ffi::dbus_connection_send(self.conn(), msg.ptr(), &mut serial) };
+ if r == 0 { return Err(()); }
+ Ok(serial)
+ }
+
+ /// Flush the queue of outgoing messages.
+ ///
+ /// Blocking: until the outgoing queue is empty.
+ pub fn flush(&self) { unsafe { ffi::dbus_connection_flush(self.conn()) } }
+
+ /// Read and write to the connection.
+ ///
+ /// Incoming messages are put in the internal queue, outgoing messages are written.
+ ///
+ /// Blocking: If there are no messages, for up to timeout_ms milliseconds, or forever if timeout_ms is None.
+ /// For non-blocking behaviour, set timeout_ms to Some(0).
+ pub fn read_write(&self, timeout_ms: Option<i32>) -> Result<(), ()> {
+ let t = timeout_ms.unwrap_or(-1);
+ if unsafe { ffi::dbus_connection_read_write(self.conn(), t) == 0 } {
+ Err(())
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Removes a message from the incoming queue, or returns None if the queue is empty.
+ ///
+ /// Use "read_write" first, so that messages are put into the incoming queue.
+ /// For unhandled messages, please call MessageDispatcher::default_dispatch to return
+ /// default replies for method calls.
+ pub fn pop_message(&self) -> Option<Message> {
+ let mptr = unsafe { ffi::dbus_connection_pop_message(self.conn()) };
+ if mptr == ptr::null_mut() {
+ None
+ } else {
+ Some(Message::from_ptr(mptr, false))
+ }
+ }
+
+ /// Get an up-to-date list of file descriptors to watch.
+ ///
+ /// Might be changed into something that allows for callbacks when the watch list is changed.
+ pub fn watch_fds(&mut self) -> Result<Vec<Watch>, ()> {
+ extern "C" fn add_watch_cb(watch: *mut ffi::DBusWatch, data: *mut c_void) -> u32 {
+ unsafe {
+ let wlist: &mut Vec<Watch> = &mut *(data as *mut _);
+ wlist.push(Watch::from_raw(watch));
+ }
+ 1
+ }
+ let mut r = vec!();
+ if unsafe { ffi::dbus_connection_set_watch_functions(self.conn(),
+ Some(add_watch_cb), None, None, &mut r as *mut _ as *mut _, None) } == 0 { return Err(()) }
+ assert!(unsafe { ffi::dbus_connection_set_watch_functions(self.conn(),
+ None, None, None, ptr::null_mut(), None) } != 0);
+ Ok(r)
+ }
+}
+
+#[test]
+fn test_txrx_send_sync() {
+ fn is_send<T: Send>(_: &T) {}
+ fn is_sync<T: Sync>(_: &T) {}
+ let c = TxRx::get_private(BusType::Session).unwrap();
+ is_send(&c);
+ is_sync(&c);
+}
+
+#[test]
+fn txrx_simple_test() {
+ let mut c = TxRx::get_private(BusType::Session).unwrap();
+ assert!(c.is_connected());
+ let fds = c.watch_fds().unwrap();
+ println!("{:?}", fds);
+ assert!(fds.len() > 0);
+ let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
+ let reply = c.send(m).unwrap();
+ let my_name = c.unique_name().unwrap();
+ loop {
+ while let Some(mut msg) = c.pop_message() {
+ println!("{:?}", msg);
+ if msg.get_reply_serial() == Some(reply) {
+ let r = msg.as_result().unwrap();
+ let z: ::arg::Array<&str, _> = r.get1().unwrap();
+ for n in z {
+ println!("{}", n);
+ if n == my_name { return; } // Hooray, we found ourselves!
+ }
+ assert!(false);
+ } else if let Some(r) = crate::MessageDispatcher::<()>::default_dispatch(&msg) {
+ c.send(r).unwrap();
+ }
+ }
+ c.read_write(Some(100)).unwrap();
+ }
+}
+
diff --git a/third_party/rust/dbus/src/crossroads/crossroads.rs b/third_party/rust/dbus/src/crossroads/crossroads.rs
new file mode 100644
index 0000000000..a856a6597c
--- /dev/null
+++ b/third_party/rust/dbus/src/crossroads/crossroads.rs
@@ -0,0 +1,245 @@
+use std::collections::BTreeMap;
+use std::any::{TypeId, Any};
+use std::ffi::{CString, CStr};
+use std::fmt;
+use crate::{Path as PathName, Interface as IfaceName, Member as MemberName, Signature, Message, MessageType};
+use super::info::{IfaceInfo, MethodInfo, PropInfo, IfaceInfoBuilder};
+use super::handlers::{Handlers, Par, ParInfo, Mut, MutCtx, MutMethods};
+use super::stdimpl::DBusProperties;
+
+// The key is an IfaceName, but if we have that we bump into https://github.com/rust-lang/rust/issues/59732
+// so we use CString as a workaround.
+#[derive(Default, Debug)]
+struct IfaceReg<H: Handlers>(BTreeMap<CString, (TypeId, IfaceInfo<'static, H>)>);
+
+#[derive(Default)]
+pub struct PathData<H: Handlers>(Vec<(TypeId, H::Iface)>);
+
+impl PathData<Par> {
+ pub fn insert_par<I: Any + 'static + Send + Sync>(&mut self, i: I) {
+ let id = TypeId::of::<I>();
+ let t = Box::new(i);
+ self.0.push((id, t));
+ }
+}
+
+impl PathData<Mut> {
+ pub fn insert_mut<I: Any + 'static>(&mut self, i: I) {
+ let id = TypeId::of::<I>();
+ let t = Box::new(i);
+ self.0.push((id, t));
+ }
+}
+
+impl<H: Handlers> fmt::Debug for PathData<H> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "...") }
+}
+
+impl<H: Handlers> PathData<H> {
+ fn new() -> Self { PathData(vec!()) }
+}
+
+#[derive(Debug)]
+struct IfacePaths<H: Handlers>(BTreeMap<CString, PathData<H>>);
+
+impl<H: Handlers> Default for IfacePaths<H> {
+ fn default() -> Self { IfacePaths(BTreeMap::new()) }
+}
+
+struct MsgHeaders<'a> {
+ m: MemberName<'a>,
+ i: IfaceName<'a>,
+ p: PathName<'a>,
+}
+
+fn msg_headers(msg: &Message) -> Option<MsgHeaders> {
+ if msg.msg_type() != MessageType::MethodCall { return None };
+ let p = msg.path()?;
+ let i = msg.interface()?;
+ let m = msg.member()?;
+ Some(MsgHeaders { m, i, p })
+}
+
+#[derive(Debug)]
+pub (super) struct MLookup<'a, H: Handlers> {
+ pub (super) cr: &'a Crossroads<H>,
+ pub (super) data: &'a PathData<H>,
+ pub (super) iface: &'a H::Iface,
+ pub (super) iinfo: &'a IfaceInfo<'static, H>,
+// pub (super) minfo: Option<&'a MethodInfo<'static, H>>,
+// pub (super) pinfo: Option<&'a PropInfo<'static, H>>,
+}
+
+#[derive(Debug)]
+pub struct Crossroads<H: Handlers> {
+ reg: IfaceReg<H>,
+ paths: IfacePaths<H>,
+}
+
+impl<H: Handlers> Crossroads<H> {
+
+ pub fn register_custom<I: 'static>(&mut self, info: IfaceInfo<'static, H>) -> Option<IfaceInfo<'static, H>> {
+ self.reg.0.insert(info.name.clone().into_cstring(), (TypeId::of::<I>(), info)).map(|x| x.1)
+ }
+ pub fn insert<N: Into<PathName<'static>>>(&mut self, name: N, data: PathData<H>) {
+ self.paths.0.insert(name.into().into_cstring(), data);
+ }
+ pub fn get_data<N: Into<PathName<'static>>>(&self, name: N) -> Option<&PathData<H>> {
+ self.paths.0.get(name.into().as_cstr())
+ }
+
+ pub fn register<'a, I: 'static, N: Into<IfaceName<'static>>>(&'a mut self, name: N) -> IfaceInfoBuilder<'a, I, H> {
+ IfaceInfoBuilder::new(Some(self), name.into())
+ }
+
+ fn reg_lookup(&self, headers: &MsgHeaders) -> Option<(MLookup<H>, &MethodInfo<'static, H>)> {
+ let (typeid, iinfo) = self.reg.0.get(headers.i.as_cstr())?;
+ let minfo = iinfo.methods.iter().find(|x| x.name() == &headers.m)?;
+ let data = self.paths.0.get(headers.p.as_cstr())?;
+ let (_, iface) = data.0.iter().find(|x| x.0 == *typeid)?;
+ Some((MLookup { cr: self, data, iface, iinfo }, minfo))
+ }
+
+ pub (super) fn reg_prop_lookup<'a>(&'a self, data: &'a PathData<H>, iname: &CStr, propname: &CStr) ->
+ Option<(MLookup<'a, H>, &PropInfo<'static, H>)> {
+ let (typeid, iinfo) = self.reg.0.get(iname)?;
+ let pinfo = iinfo.props.iter().find(|x| x.name.as_cstr() == propname)?;
+ let (_, iface) = data.0.iter().find(|x| x.0 == *typeid)?;
+ Some((MLookup { cr: self, data, iface, iinfo}, pinfo))
+ }
+}
+
+impl Crossroads<Par> {
+ pub fn dispatch_par(&self, msg: &Message) -> Option<Vec<Message>> {
+ let headers = msg_headers(msg)?;
+ let (lookup, minfo) = self.reg_lookup(&headers)?;
+ let handler = minfo.handler();
+ let iface = &**lookup.iface;
+ let mut info = ParInfo::new(msg, lookup);
+ let r = (handler)(iface, &mut info);
+ Some(r.into_iter().collect())
+ }
+
+ pub fn new_par() -> Self {
+ let mut cr = Crossroads {
+ reg: IfaceReg(BTreeMap::new()),
+ paths: IfacePaths(BTreeMap::new()),
+ };
+ DBusProperties::register(&mut cr);
+ cr
+ }
+}
+
+impl Crossroads<Mut> {
+ pub fn dispatch_mut(&mut self, msg: &Message) -> Option<Vec<Message>> {
+ let headers = msg_headers(msg)?;
+ let (typeid, iinfo) = self.reg.0.get_mut(headers.i.as_cstr())?;
+ let minfo = iinfo.methods.iter_mut().find(|x| x.name() == &headers.m)?;
+ let ctx = MutCtx::new(msg);
+ let r = match minfo.handler_mut().0 {
+ MutMethods::MutIface(ref mut f) => {
+ let data = self.paths.0.get_mut(headers.p.as_cstr())?;
+ let (_, iface) = data.0.iter_mut().find(|x| x.0 == *typeid)?;
+ let iface = &mut **iface;
+ f(iface, &ctx)
+ }
+ };
+ Some(r.into_iter().collect())
+ }
+
+ pub fn new_mut() -> Self {
+ let cr = Crossroads {
+ reg: IfaceReg(BTreeMap::new()),
+ paths: IfacePaths(BTreeMap::new()),
+ };
+ // DBusProperties::register(&mut cr);
+ cr
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_send_sync() {
+ fn is_send<T: Send>(_: &T) {}
+ fn is_sync<T: Sync>(_: &T) {}
+ let c = Crossroads::new_par();
+ dbg!(&c);
+ is_send(&c);
+ is_sync(&c);
+ }
+
+ #[test]
+ fn cr_mut() {
+ let mut cr = Crossroads::new_mut();
+
+ struct Score(u16);
+
+ let mut call_times = 0u32;
+ cr.register::<Score,_>("com.example.dbusrs.crossroads.score")
+ .method_iface("UpdateScore", ("change",), ("new_score", "call_times"), move |score, _, (change,): (u16,)| {
+ score.0 += change;
+ call_times += 1;
+ Ok((score.0, call_times))
+ });
+
+ let mut pdata = PathData::new();
+ pdata.insert_mut(Score(7u16));
+ cr.insert("/", pdata);
+
+ let msg = Message::new_method_call("com.example.dbusrs.crossroads.score", "/", "com.example.dbusrs.crossroads.score", "UpdateScore").unwrap();
+ let mut msg = msg.append1(5u16);
+ crate::message::message_set_serial(&mut msg, 57);
+ let mut r = cr.dispatch_mut(&msg).unwrap();
+ assert_eq!(r.len(), 1);
+ r[0].as_result().unwrap();
+ let (new_score, call_times): (u16, u32) = r[0].read2().unwrap();
+ assert_eq!(new_score, 12);
+ assert_eq!(call_times, 1);
+ }
+
+
+ #[test]
+ fn cr_par() {
+ let mut cr = Crossroads::new_par();
+
+ struct Score(u16);
+
+ cr.register::<Score,_>("com.example.dbusrs.crossroads.score")
+ .method("Hello", ("sender",), ("reply",), |score, _, (sender,): (String,)| {
+ assert_eq!(score.0, 7u16);
+ Ok((format!("Hello {}, my score is {}!", sender, score.0),))
+ })
+ .prop_ro("Score", |score, _| {
+ assert_eq!(score.0, 7u16);
+ Ok(score.0)
+ })
+ .signal::<(u16,),_>("ScoreChanged", ("NewScore",));
+
+ let mut pdata = PathData::new();
+ pdata.insert_par(Score(7u16));
+ pdata.insert_par(DBusProperties);
+ cr.insert("/", pdata);
+
+ let msg = Message::new_method_call("com.example.dbusrs.crossroads.score", "/", "com.example.dbusrs.crossroads.score", "Hello").unwrap();
+ let mut msg = msg.append1("example");
+ crate::message::message_set_serial(&mut msg, 57);
+ let mut r = cr.dispatch_par(&msg).unwrap();
+ assert_eq!(r.len(), 1);
+ r[0].as_result().unwrap();
+ let rr: String = r[0].read1().unwrap();
+ assert_eq!(&rr, "Hello example, my score is 7!");
+
+ let msg = Message::new_method_call("com.example.dbusrs.crossroads.score", "/", "org.freedesktop.DBus.Properties", "Get").unwrap();
+ let mut msg = msg.append2("com.example.dbusrs.crossroads.score", "Score");
+ crate::message::message_set_serial(&mut msg, 57);
+ let mut r = cr.dispatch_par(&msg).unwrap();
+ assert_eq!(r.len(), 1);
+ r[0].as_result().unwrap();
+ let z: u16 = r[0].read1().unwrap();
+ assert_eq!(z, 7u16);
+ }
+}
diff --git a/third_party/rust/dbus/src/crossroads/handlers.rs b/third_party/rust/dbus/src/crossroads/handlers.rs
new file mode 100644
index 0000000000..2d466ba119
--- /dev/null
+++ b/third_party/rust/dbus/src/crossroads/handlers.rs
@@ -0,0 +1,138 @@
+use std::{fmt, cell};
+use std::any::Any;
+use crate::arg::ArgBuilder;
+use crate::{Path as PathName, Interface as IfaceName, Member as MemberName, Signature, Message, arg};
+use super::crossroads::{Crossroads, PathData, MLookup};
+use super::info::{MethodInfo, PropInfo};
+use super::MethodErr;
+
+pub struct DebugMethod<H: Handlers>(pub H::Method);
+impl<H: Handlers> fmt::Debug for DebugMethod<H> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "...") }
+}
+
+pub struct DebugProp<H: Handlers>(pub Option<H::GetProp>, pub Option<H::SetProp>);
+impl<H: Handlers> fmt::Debug for DebugProp<H> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "...") }
+}
+
+pub trait Handlers {
+ type Method;
+ type GetProp;
+ type SetProp;
+ type Iface;
+}
+
+/// Parallel tree - Par
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Par;
+
+impl Par {
+ pub fn typed_getprop<I: 'static, T: arg::Arg + arg::Append, G>(getf: G) -> <Par as Handlers>::GetProp
+ where G: Fn(&I, &ParInfo) -> Result<T, MethodErr> + Send + Sync + 'static {
+ Box::new(move |data, ia, info| {
+ let iface: &I = data.downcast_ref().unwrap();
+ let t = getf(iface, info)?;
+ ia.append(t);
+ Ok(())
+ })
+ }
+
+ pub fn typed_setprop<I: 'static, T: arg::Arg + for <'z> arg::Get<'z>, S>(setf: S) -> <Par as Handlers>::SetProp
+ where S: Fn(&I, &ParInfo, T) -> Result<(), MethodErr> + Send + Sync + 'static {
+ Box::new(move |data, ii, info| {
+ let iface: &I = data.downcast_ref().unwrap();
+ let t: T = ii.read()?;
+ setf(iface, info, t)
+ })
+ }
+}
+
+#[derive(Debug)]
+pub struct ParInfo<'a> {
+ lookup: MLookup<'a, Par>,
+ message: &'a Message,
+}
+
+impl<'a> ParInfo<'a> {
+ pub fn msg(&self) -> &Message { self.message }
+ pub (super) fn new(msg: &'a Message, lookup: MLookup<'a, Par>) -> Self {
+ ParInfo { lookup, message: msg }
+ }
+ pub fn path_data(&self) -> &PathData<Par> { self.lookup.data }
+ pub fn crossroads(&self) -> &Crossroads<Par> { self.lookup.cr }
+}
+
+impl Handlers for Par {
+ type Method = Box<Fn(&(dyn Any + Send + Sync), &ParInfo) -> Option<Message> + Send + Sync + 'static>;
+ type GetProp = Box<Fn(&(dyn Any + Send + Sync), &mut arg::IterAppend, &ParInfo) -> Result<(), MethodErr> + Send + Sync + 'static>;
+ type SetProp = Box<Fn(&(dyn Any + Send + Sync), &mut arg::Iter, &ParInfo) -> Result<(), MethodErr> + Send + Sync + 'static>;
+ type Iface = Box<dyn Any + 'static + Send + Sync>;
+}
+
+impl MethodInfo<'_, Par> {
+ pub fn new_par<N, F, T>(name: N, f: F) -> Self where
+ F: Fn(&T, &ParInfo) -> Result<Option<Message>, MethodErr> + Send + Sync + 'static,
+ N: Into<MemberName<'static>>,
+ T: Any + Send + Sync + 'static,
+ {
+ Self::new(name.into(), Box::new(move |data, info| {
+ let x = data.downcast_ref().unwrap();
+ f(x, info).unwrap_or_else(|e| { Some(e.to_message(info.message)) })
+ }))
+ }
+}
+
+
+/// Mutable, non-Send tree
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Mut;
+
+#[derive(Debug)]
+pub struct MutCtx<'a> {
+ message: &'a Message,
+ send_extra: cell::RefCell<Vec<Message>>,
+}
+
+impl<'a> MutCtx<'a> {
+ pub fn msg(&self) -> &Message { self.message }
+ pub fn send(&self, msg: Message) { self.send_extra.borrow_mut().push(msg); }
+ pub (super) fn new(msg: &'a Message) -> Self { MutCtx { message: msg, send_extra: Default::default() } }
+}
+
+impl Handlers for Mut {
+ type Method = MutMethod;
+ type GetProp = Box<FnMut(&mut (dyn Any), &mut arg::IterAppend, &MutCtx) -> Result<(), MethodErr> + 'static>;
+ type SetProp = Box<FnMut(&mut (dyn Any), &mut arg::Iter, &MutCtx) -> Result<(), MethodErr> + 'static>;
+ type Iface = Box<dyn Any>;
+}
+
+
+pub struct MutMethod(pub (super) MutMethods);
+
+pub (super) enum MutMethods {
+ MutIface(Box<FnMut(&mut (dyn Any), &MutCtx) -> Option<Message> + 'static>),
+// Info(Box<FnMut(&(dyn Any), &Message, &Path) -> Option<Message> + 'static>),
+// MutCr(fn(&mut Crossroads<Mut>, &Message) -> Vec<Message>),
+}
+
+impl Mut {
+ pub fn typed_method_iface<IA: ArgBuilder, OA: ArgBuilder, I: 'static, F>(mut f: F) -> <Mut as Handlers>::Method
+ where F: FnMut(&mut I, &MutCtx, IA) -> Result<OA, MethodErr> + 'static {
+ MutMethod(MutMethods::MutIface(Box::new(move |data, info| {
+ let iface: &mut I = data.downcast_mut().unwrap();
+ let ia = match IA::read(info.msg()) {
+ Err(e) => return Some(MethodErr::from(e).to_message(info.msg())),
+ Ok(ia) => ia,
+ };
+ match f(iface, info, ia) {
+ Err(e) => Some(e.to_message(info.msg())),
+ Ok(r) => {
+ let mut m = info.msg().method_return();
+ OA::append(r, &mut m);
+ Some(m)
+ },
+ }
+ })))
+ }
+}
diff --git a/third_party/rust/dbus/src/crossroads/info.rs b/third_party/rust/dbus/src/crossroads/info.rs
new file mode 100644
index 0000000000..655b3193de
--- /dev/null
+++ b/third_party/rust/dbus/src/crossroads/info.rs
@@ -0,0 +1,220 @@
+use crate::{Path as PathName, Interface as IfaceName, Member as MemberName, Signature, Message};
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+use std::any::Any;
+use std::mem;
+use crate::arg::{Arg, Append, Get, ArgBuilder, TypeMismatchError, IterAppend};
+use std::marker::PhantomData;
+use super::MethodErr;
+use super::handlers::{Handlers, DebugMethod, DebugProp, Par, ParInfo, Mut, MutCtx};
+use super::crossroads::{Crossroads, PathData};
+
+fn build_argvec<A: ArgBuilder>(a: A::strs) -> Vec<Argument<'static>> {
+ let mut v = vec!();
+ A::strs_sig(a, |name, sig| {
+ v.push(Argument { name: name.into(), sig })
+ });
+ v
+}
+
+
+#[derive(Default, Debug, Clone)]
+struct Annotations(Option<BTreeMap<String, String>>);
+
+#[derive(Debug, Clone)]
+pub struct Argument<'a> {
+ name: Cow<'a, str>,
+ sig: Signature<'a>,
+}
+
+#[derive(Debug)]
+pub struct IfaceInfo<'a, H: Handlers> {
+ pub (crate) name: IfaceName<'a>,
+ pub (crate) methods: Vec<MethodInfo<'a, H>>,
+ pub (crate) props: Vec<PropInfo<'a, H>>,
+ pub (crate) signals: Vec<SignalInfo<'a>>,
+}
+
+#[derive(Debug)]
+pub struct MethodInfo<'a, H: Handlers> {
+ name: MemberName<'a>,
+ handler: DebugMethod<H>,
+ i_args: Vec<Argument<'a>>,
+ o_args: Vec<Argument<'a>>,
+ anns: Annotations,
+}
+
+impl<'a, H: Handlers> MethodInfo<'a, H> {
+ pub fn name(&self) -> &MemberName<'a> { &self.name }
+ pub fn handler(&self) -> &H::Method { &self.handler.0 }
+ pub fn handler_mut(&mut self) -> &mut H::Method { &mut self.handler.0 }
+}
+
+#[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,
+}
+
+#[derive(Debug)]
+pub struct PropInfo<'a, H: Handlers> {
+ pub (crate) name: MemberName<'a>,
+ pub (crate) handlers: DebugProp<H>,
+ anns: Annotations,
+ sig: Signature<'a>,
+ emits: EmitsChangedSignal,
+ auto_emit: bool,
+ rw: Access,
+}
+
+#[derive(Debug)]
+pub struct SignalInfo<'a> {
+ name: MemberName<'a>,
+ args: Vec<Argument<'a>>,
+ anns: Annotations,
+}
+
+#[derive(Debug)]
+pub struct IfaceInfoBuilder<'a, I: 'static, H: Handlers> {
+ cr: Option<&'a mut Crossroads<H>>,
+ info: IfaceInfo<'static, H>,
+ _dummy: PhantomData<*const I>,
+}
+
+impl<'a, I, H: Handlers> IfaceInfoBuilder<'a, I, H> {
+ pub fn new(cr: Option<&'a mut Crossroads<H>>, name: IfaceName<'static>) -> Self {
+ IfaceInfoBuilder { cr, _dummy: PhantomData, info: IfaceInfo::new_empty(name) }
+ }
+
+ pub fn signal<A: ArgBuilder, N: Into<MemberName<'static>>>(mut self, name: N, args: A::strs) -> Self {
+ let s = SignalInfo { name: name.into(), args: build_argvec::<A>(args), anns: Default::default() };
+ self.info.signals.push(s);
+ self
+ }
+}
+
+impl<'a, I: 'static, H: Handlers> Drop for IfaceInfoBuilder<'a, I, H> {
+ fn drop(&mut self) {
+ if let Some(ref mut cr) = self.cr {
+ let info = IfaceInfo::new_empty(self.info.name.clone()); // workaround for not being able to consume self.info
+ cr.register_custom::<I>(mem::replace(&mut self.info, info));
+ }
+ }
+}
+
+impl<'a, I: 'static> IfaceInfoBuilder<'a, I, Par> {
+ pub fn method<IA: ArgBuilder, OA: ArgBuilder, N, F>(mut self, name: N, in_args: IA::strs, out_args: OA::strs, f: F) -> Self
+ where N: Into<MemberName<'static>>, F: Fn(&I, &ParInfo, IA) -> Result<OA, MethodErr> + Send + Sync + 'static {
+ let f: <Par as Handlers>::Method = Box::new(move |data, info| {
+ let iface: &I = data.downcast_ref().unwrap();
+ let r = IA::read(info.msg()).map_err(From::from);
+ let r = r.and_then(|ia| f(iface, info, ia));
+ match r {
+ Err(e) => Some(e.to_message(info.msg())),
+ Ok(r) => {
+ let mut m = info.msg().method_return();
+ OA::append(r, &mut m);
+ Some(m)
+ },
+ }
+ });
+
+ let m = MethodInfo { name: name.into(), handler: DebugMethod(f),
+ i_args: build_argvec::<IA>(in_args), o_args: build_argvec::<OA>(out_args), anns: Default::default() };
+ self.info.methods.push(m);
+ self
+ }
+
+ pub fn prop_rw<T, N, G, S>(mut self, name: N, getf: G, setf: S) -> Self
+ where T: Arg + Append + for<'z> Get<'z> + Send + Sync + 'static,
+ N: Into<MemberName<'static>>,
+ G: Fn(&I, &ParInfo) -> Result<T, MethodErr> + Send + Sync + 'static,
+ S: Fn(&I, &ParInfo, T) -> Result<(), MethodErr> + Send + Sync + 'static
+ {
+ let p = PropInfo::new(name.into(), T::signature(), Some(Par::typed_getprop(getf)), Some(Par::typed_setprop(setf)));
+ self.info.props.push(p);
+ self
+ }
+
+ pub fn prop_ro<T, N, G>(mut self, name: N, getf: G) -> Self
+ where T: Arg + Append + Send + Sync + 'static,
+ N: Into<MemberName<'static>>,
+ G: Fn(&I, &ParInfo) -> Result<T, MethodErr> + Send + Sync + 'static,
+ {
+ let p = PropInfo::new(name.into(), T::signature(), Some(Par::typed_getprop(getf)), None);
+ self.info.props.push(p);
+ self
+ }
+
+}
+
+impl<'a, I: 'static> IfaceInfoBuilder<'a, I, Mut> {
+ pub fn method_iface<IA: ArgBuilder, OA: ArgBuilder, N, F>(mut self, name: N, in_args: IA::strs, out_args: OA::strs, f: F) -> Self
+ where N: Into<MemberName<'static>>, F: FnMut(&mut I, &MutCtx, IA) -> Result<OA, MethodErr> + Send + Sync + 'static {
+ let m = MethodInfo { name: name.into(), handler: DebugMethod(Mut::typed_method_iface(f)),
+ i_args: build_argvec::<IA>(in_args), o_args: build_argvec::<OA>(out_args), anns: Default::default() };
+ self.info.methods.push(m);
+ self
+ }
+}
+
+impl<H: Handlers> MethodInfo<'_, H> {
+ pub fn new(name: MemberName<'static>, f: H::Method) -> Self {
+ MethodInfo { name: name, handler: DebugMethod(f),
+ i_args: Default::default(), o_args: Default::default(), anns: Default::default() }
+ }
+}
+
+impl<H: Handlers> PropInfo<'_, H> {
+ pub fn new(name: MemberName<'static>, sig: Signature<'static>, get: Option<H::GetProp>,
+ set: Option<H::SetProp>) -> Self {
+ let a = match (&get, &set) {
+ (Some(_), Some(_)) => Access::ReadWrite,
+ (Some(_), None) => Access::Read,
+ (None, Some(_)) => Access::Write,
+ _ => unimplemented!(),
+ };
+ PropInfo { name, handlers: DebugProp(get, set), sig, auto_emit: true, rw: a,
+ emits: EmitsChangedSignal::True, anns: Default::default() }
+ }
+}
+
+impl<'a, H: Handlers> IfaceInfo<'a, H> {
+ pub fn new_empty(name: IfaceName<'static>) -> Self {
+ IfaceInfo { name, methods: vec!(), props: vec!(), signals: vec!() }
+ }
+
+ pub fn new<N, M, P, S>(name: N, methods: M, properties: P, signals: S) -> Self where
+ N: Into<IfaceName<'a>>,
+ M: IntoIterator<Item=MethodInfo<'a, H>>,
+ P: IntoIterator<Item=PropInfo<'a, H>>,
+ S: IntoIterator<Item=SignalInfo<'a>>
+ {
+ IfaceInfo {
+ name: name.into(),
+ methods: methods.into_iter().collect(),
+ props: properties.into_iter().collect(),
+ signals: signals.into_iter().collect()
+ }
+ }
+}
+
diff --git a/third_party/rust/dbus/src/crossroads/mod.rs b/third_party/rust/dbus/src/crossroads/mod.rs
new file mode 100644
index 0000000000..7915157bc1
--- /dev/null
+++ b/third_party/rust/dbus/src/crossroads/mod.rs
@@ -0,0 +1,15 @@
+//! Will eventually superseed the "tree" module. It's unstable and experimental for now.
+#![allow(unused_imports, dead_code, missing_docs)]
+
+mod info;
+mod handlers;
+mod crossroads;
+mod stdimpl;
+
+pub use crate::tree::MethodErr as MethodErr;
+
+pub use self::info::{IfaceInfo, MethodInfo, PropInfo};
+
+pub use self::crossroads::{Crossroads, PathData};
+
+pub use self::handlers::{Handlers, Par, ParInfo};
diff --git a/third_party/rust/dbus/src/crossroads/stdimpl.rs b/third_party/rust/dbus/src/crossroads/stdimpl.rs
new file mode 100644
index 0000000000..10729da5b1
--- /dev/null
+++ b/third_party/rust/dbus/src/crossroads/stdimpl.rs
@@ -0,0 +1,53 @@
+use super::crossroads::Crossroads;
+use super::handlers::{ParInfo, Par};
+use super::info::{IfaceInfo, MethodInfo, PropInfo};
+use crate::arg;
+use super::MethodErr;
+
+pub struct DBusProperties;
+
+impl DBusProperties {
+ pub fn register(cr: &mut Crossroads<Par>) {
+ cr.register_custom::<Self>(IfaceInfo::new("org.freedesktop.DBus.Properties",
+ vec!(MethodInfo::new_par("Get", |_: &DBusProperties, info| {
+ let (iname, propname) = info.msg().read2()?;
+ let (lookup, pinfo) = info.crossroads().reg_prop_lookup(info.path_data(), iname, propname)
+ .ok_or_else(|| { MethodErr::no_property(&"Could not find property") })?;
+ let handler = &pinfo.handlers.0.as_ref()
+ .ok_or_else(|| { MethodErr::no_property(&"Property can not be read") })?;
+ let iface = &**lookup.iface;
+ let mut pinfo = ParInfo::new(info.msg(), lookup);
+ let mut mret = info.msg().method_return();
+ {
+ let mut ia = arg::IterAppend::new(&mut mret);
+ (handler)(iface, &mut ia, &mut pinfo)?;
+ }
+ Ok(Some(mret))
+ })),
+ vec!(), vec!()
+ ));
+
+ }
+}
+
+pub struct DBusIntrospectable;
+
+use crate::crossroads as cr;
+
+pub trait Introspectable {
+ fn introspect(&self, info: &cr::ParInfo) -> Result<String, cr::MethodErr>;
+}
+
+pub fn introspectable_ifaceinfo<I>() -> cr::IfaceInfo<'static, cr::Par>
+where I: Introspectable + Send + Sync + 'static {
+ cr::IfaceInfo::new("org.freedesktop.DBus.Introspectable", vec!(
+ MethodInfo::new_par("Introspect", |intf: &I, info| {
+ let xml_data = intf.introspect(info)?;
+ let rm = info.msg().method_return();
+ let rm = rm.append1(xml_data);
+ Ok(Some(rm))
+ }),
+ ), vec!(), vec!())
+}
+
+
diff --git a/third_party/rust/dbus/src/dispatcher.rs b/third_party/rust/dbus/src/dispatcher.rs
new file mode 100644
index 0000000000..eda78ed586
--- /dev/null
+++ b/third_party/rust/dbus/src/dispatcher.rs
@@ -0,0 +1,129 @@
+use crate::{Message, MessageType, Error, to_c_str, c_str_to_slice};
+use std::ptr;
+
+use std::collections::HashMap;
+
+/// [Unstable and Experimental]
+pub trait MessageDispatcherConfig: Sized {
+ /// The type of method reply stored inside the dispatcher
+ type Reply;
+
+ /// Called when a method call has received a reply.
+ fn on_reply(reply: Self::Reply, msg: Message, dispatcher: &mut MessageDispatcher<Self>);
+
+ /// Called when a signal is received.
+ ///
+ /// Defaults to doing nothing.
+ #[allow(unused_variables)]
+ fn on_signal(msg: Message, dispatcher: &mut MessageDispatcher<Self>) {}
+
+ /// Called when a method call is received.
+ ///
+ /// Defaults to calling default_dispatch.
+ fn on_method_call(msg: Message, dispatcher: &mut MessageDispatcher<Self>) {
+ if let Some(reply) = MessageDispatcher::<Self>::default_dispatch(&msg) {
+ Self::on_send(reply, dispatcher);
+ }
+ }
+
+ /// Called in the other direction, i e, when a message should be sent over the connection.
+ fn on_send(msg: Message, dispatcher: &mut MessageDispatcher<Self>);
+}
+
+/// Dummy implementation
+impl MessageDispatcherConfig for () {
+ type Reply = ();
+ fn on_reply(_: Self::Reply, _: Message, _: &mut MessageDispatcher<Self>) { unreachable!() }
+ fn on_send(_: Message, _: &mut MessageDispatcher<Self>) { unreachable!() }
+}
+
+/// [Unstable and Experimental] Meant for usage with RxTx.
+pub struct MessageDispatcher<C: MessageDispatcherConfig> {
+ waiting_replies: HashMap<u32, C::Reply>,
+ inner: C,
+}
+
+impl<C: MessageDispatcherConfig> MessageDispatcher<C> {
+
+ /// Creates a new message dispatcher.
+ pub fn new(inner: C) -> Self { MessageDispatcher {
+ waiting_replies: HashMap::new(),
+ inner: inner,
+ } }
+
+ /// "Inner" accessor
+ pub fn inner(&self) -> &C { &self.inner }
+
+ /// "Inner" mutable accessor
+ pub fn inner_mut(&mut self) -> &mut C { &mut self.inner }
+
+ /// Adds a waiting reply to a method call. func will be called when a method reply is dispatched.
+ pub fn add_reply(&mut self, serial: u32, func: C::Reply) {
+ if let Some(_) = self.waiting_replies.insert(serial, func) {
+ // panic because we're overwriting something else, or just ignore?
+ }
+ }
+
+ /// Cancels a waiting reply.
+ pub fn cancel_reply(&mut self, serial: u32) -> Option<C::Reply> {
+ self.waiting_replies.remove(&serial)
+ }
+
+
+ /// Dispatch an incoming message.
+ pub fn dispatch(&mut self, msg: Message) {
+ if let Some(serial) = msg.get_reply_serial() {
+ if let Some(sender) = self.waiting_replies.remove(&serial) {
+ C::on_reply(sender, msg, self);
+ return;
+ }
+ }
+ match msg.msg_type() {
+ MessageType::Signal => C::on_signal(msg, self),
+ MessageType::MethodCall => C::on_method_call(msg, self),
+ MessageType::Error | MessageType::MethodReturn => {},
+ MessageType::Invalid => unreachable!(),
+ }
+ }
+
+ /// Handles what we need to be a good D-Bus citizen.
+ ///
+ /// Call this if you have not handled the message yourself:
+ /// * It handles calls to org.freedesktop.DBus.Peer.
+ /// * For other method calls, it sends an error reply back that the method was unknown.
+ pub fn default_dispatch(m: &Message) -> Option<Message> {
+ Self::peer(&m)
+ .or_else(|| Self::unknown_method(&m))
+ }
+
+ /// Replies if this is a call to org.freedesktop.DBus.Peer, otherwise returns None.
+ pub fn peer(m: &Message) -> Option<Message> {
+ if let Some(intf) = m.interface() {
+ if &*intf != "org.freedesktop.DBus.Peer" { return None; }
+ if let Some(method) = m.member() {
+ if &*method == "Ping" { return Some(m.method_return()) }
+ if &*method == "GetMachineId" {
+ let mut r = m.method_return();
+ let mut e = Error::empty();
+ unsafe {
+ let id = ffi::dbus_try_get_local_machine_id(e.get_mut());
+ if id != ptr::null_mut() {
+ r = r.append1(c_str_to_slice(&(id as *const _)).unwrap());
+ ffi::dbus_free(id as *mut _);
+ return Some(r)
+ }
+ }
+ }
+ }
+ Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Method does not exist")))
+ } else { None }
+ }
+
+ /// For method calls, it replies that the method was unknown, otherwise returns None.
+ pub fn unknown_method(m: &Message) -> Option<Message> {
+ if m.msg_type() != MessageType::MethodCall { return None; }
+ // if m.get_no_reply() { return None; } // The reference implementation does not do this?
+ Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Path, Interface, or Method does not exist")))
+ }
+}
+
diff --git a/third_party/rust/dbus/src/lib.rs b/third_party/rust/dbus/src/lib.rs
new file mode 100644
index 0000000000..6a56671490
--- /dev/null
+++ b/third_party/rust/dbus/src/lib.rs
@@ -0,0 +1,284 @@
+//! 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 matchrule;
+pub use matchrule::MatchRule;
+
+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);
+ }
+}
diff --git a/third_party/rust/dbus/src/matchrule.rs b/third_party/rust/dbus/src/matchrule.rs
new file mode 100644
index 0000000000..fb42abe51b
--- /dev/null
+++ b/third_party/rust/dbus/src/matchrule.rs
@@ -0,0 +1,77 @@
+use crate::{Message, MessageType, BusName, Path, Interface, Member};
+
+
+#[derive(Clone, Debug, Default)]
+/// A "match rule", that can match Messages on its headers.
+///
+/// A field set to "None" means no filter for that header,
+/// a field set to "Some(_)" must match exactly.
+pub struct MatchRule<'a> {
+ /// Match on message type (you typically want to do this)
+ pub msg_type: Option<MessageType>,
+ /// Match on message sender
+ pub sender: Option<BusName<'a>>,
+ /// Match on message object path
+ pub path: Option<Path<'a>>,
+ /// Match on message interface
+ pub interface: Option<Interface<'a>>,
+ /// Match on message member (signal or method name)
+ pub member: Option<Member<'a>>,
+ _more_fields_may_come: (),
+}
+
+fn msg_type_str(m: MessageType) -> &'static str {
+ use MessageType::*;
+ match m {
+ Signal => "signal",
+ MethodCall => "method_call",
+ MethodReturn => "method_return",
+ Error => "error",
+ Invalid => unreachable!(),
+ }
+}
+
+
+impl<'a> MatchRule<'a> {
+ /// Make a string which you can use in the call to "add_match".
+ ///
+ /// Panics: if msg_type is set to Some(MessageType::Invalid)
+ pub fn match_str(&self) -> String {
+ let mut v = vec!();
+ if let Some(x) = self.msg_type { v.push(("type", msg_type_str(x))) };
+ if let Some(ref x) = self.sender { v.push(("sender", &x)) };
+ if let Some(ref x) = self.path { v.push(("path", &x)) };
+ if let Some(ref x) = self.interface { v.push(("interface", &x)) };
+ if let Some(ref x) = self.member { v.push(("member", &x)) };
+
+ // For now we don't need to worry about internal quotes in strings as those are not valid names.
+ // If we start matching against arguments, we need to worry.
+ let v: Vec<_> = v.into_iter().map(|(k, v)| format!("{}='{}'", k, v)).collect();
+ v.join(",")
+ }
+
+ /// Returns whether or not the message matches the rule.
+ pub fn matches(&self, msg: &Message) -> bool {
+ if let Some(x) = self.msg_type { if x != msg.msg_type() { return false; }};
+ if self.sender.is_some() && msg.sender() != self.sender { return false };
+ if self.path.is_some() && msg.path() != self.path { return false };
+ if self.interface.is_some() && msg.interface() != self.interface { return false };
+ if self.member.is_some() && msg.member() != self.member { return false };
+ true
+ }
+
+ /// Create a new struct which matches every message.
+ pub fn new() -> Self { Default::default() }
+
+ /// Returns a clone with no static references
+ pub fn into_static(&self) -> MatchRule<'static> {
+ MatchRule {
+ msg_type: self.msg_type,
+ sender: self.sender.as_ref().map(|x| x.clone().into_static()),
+ path: self.path.as_ref().map(|x| x.clone().into_static()),
+ interface: self.interface.as_ref().map(|x| x.clone().into_static()),
+ member: self.member.as_ref().map(|x| x.clone().into_static()),
+ _more_fields_may_come: (),
+ }
+ }
+}
diff --git a/third_party/rust/dbus/src/message.rs b/third_party/rust/dbus/src/message.rs
new file mode 100644
index 0000000000..7a77dcd9a0
--- /dev/null
+++ b/third_party/rust/dbus/src/message.rs
@@ -0,0 +1,1152 @@
+use std::borrow::Cow;
+use std::{fmt, mem, ptr, ops};
+use super::{ffi, Error, MessageType, Signature, libc, to_c_str, c_str_to_slice, init_dbus};
+use super::{BusName, Path, Interface, Member, ErrorName, Connection, SignalArgs};
+use std::os::unix::io::{RawFd, AsRawFd};
+use std::ffi::CStr;
+use std::os::raw::{c_void, c_char, c_int};
+
+use super::arg::{Append, IterAppend, Get, Iter, Arg, RefArg, TypeMismatchError};
+
+#[derive(Debug,Copy,Clone)]
+/// Errors that can happen when creating a MessageItem::Array.
+pub enum ArrayError {
+ /// The array is empty.
+ EmptyArray,
+ /// The array is composed of different element types.
+ DifferentElementTypes,
+ /// The supplied signature is not a valid array signature
+ InvalidSignature,
+}
+
+fn new_dbus_message_iter() -> ffi::DBusMessageIter { unsafe { mem::zeroed() }}
+
+
+/// An RAII wrapper around Fd to ensure that file descriptor is closed
+/// when the scope ends.
+#[derive(Debug, PartialEq, PartialOrd)]
+pub struct OwnedFd {
+ fd: RawFd
+}
+
+impl OwnedFd {
+ /// Create a new OwnedFd from a RawFd.
+ pub fn new(fd: RawFd) -> OwnedFd {
+ OwnedFd { fd: fd }
+ }
+
+ /// Convert an OwnedFD back into a RawFd.
+ pub fn into_fd(self) -> RawFd {
+ let s = self.fd;
+ ::std::mem::forget(self);
+ s
+ }
+}
+
+impl Drop for OwnedFd {
+ fn drop(&mut self) {
+ unsafe { libc::close(self.fd); }
+ }
+}
+
+impl Clone for OwnedFd {
+ fn clone(&self) -> OwnedFd {
+ OwnedFd::new(unsafe { libc::dup(self.fd) } ) // FIXME: handle errors
+ }
+}
+
+impl AsRawFd for OwnedFd {
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, PartialOrd)]
+/// An array of MessageItem where every MessageItem is of the same type.
+pub struct MessageItemArray {
+ v: Vec<MessageItem>,
+ // signature includes the "a"!
+ sig: Signature<'static>,
+}
+
+impl MessageItemArray {
+ /// Creates a new array where every element has the supplied signature.
+ ///
+ /// Signature is the full array signature, not the signature of the element.
+ pub fn new(v: Vec<MessageItem>, sig: Signature<'static>) -> Result<MessageItemArray, ArrayError> {
+ let a = MessageItemArray {v: v, sig: sig };
+ if a.sig.as_bytes()[0] != ffi::DBUS_TYPE_ARRAY as u8 { return Err(ArrayError::InvalidSignature) }
+ {
+ let esig = a.element_signature();
+ for i in &a.v {
+ let b = if let MessageItem::DictEntry(ref k, ref v) = *i {
+ let s = format!("{{{}{}}}", k.signature(), v.signature());
+ s.as_bytes() == esig.to_bytes()
+ } else {
+ i.signature().as_cstr() == esig
+ };
+ if !b { return Err(ArrayError::DifferentElementTypes) }
+ }
+ }
+ Ok(a)
+ }
+
+ fn element_signature(&self) -> &CStr {
+ let z = &self.sig.as_cstr().to_bytes_with_nul()[1..];
+ unsafe { CStr::from_bytes_with_nul_unchecked(z) }
+ }
+
+ fn make_sig(m: &MessageItem) -> Signature<'static> {
+ if let MessageItem::DictEntry(ref k, ref v) = *m {
+ Signature::new(format!("a{{{}{}}}", k.signature(), v.signature())).unwrap()
+ } else {
+ Signature::new(format!("a{}", m.signature())).unwrap()
+ }
+ }
+
+ /// Signature of array (full array signature)
+ pub fn signature(&self) -> &Signature<'static> { &self.sig }
+
+ /// Consumes the MessageItemArray in order to allow you to modify the individual items of the array.
+ pub fn into_vec(self) -> Vec<MessageItem> { self.v }
+}
+
+impl ops::Deref for MessageItemArray {
+ type Target = [MessageItem];
+ fn deref(&self) -> &Self::Target { &self.v }
+}
+
+
+/// MessageItem - used as parameters and return values from
+/// method calls, or as data added to a signal (old, enum version).
+///
+/// Note that the newer generic design (see `arg` module) is both faster
+/// and less error prone than MessageItem, and should be your first hand choice
+/// whenever applicable.
+#[derive(Debug, PartialEq, PartialOrd, Clone)]
+pub enum MessageItem {
+ /// A D-Bus array requires all elements to be of the same type.
+ /// All elements must match the Signature.
+ Array(MessageItemArray),
+ /// A D-Bus struct allows for values of different types.
+ Struct(Vec<MessageItem>),
+ /// A D-Bus variant is a wrapper around another `MessageItem`, which
+ /// can be of any type.
+ Variant(Box<MessageItem>),
+ /// A D-Bus dictionary entry. These are only allowed inside an array.
+ DictEntry(Box<MessageItem>, Box<MessageItem>),
+ /// A D-Bus objectpath requires its content to be a valid objectpath,
+ /// so this cannot be any string.
+ ObjectPath(Path<'static>),
+ /// A D-Bus String is zero terminated, so no \0 s in the String, please.
+ /// (D-Bus strings are also - like Rust strings - required to be valid UTF-8.)
+ Str(String),
+ /// A D-Bus boolean type.
+ Bool(bool),
+ /// A D-Bus unsigned 8 bit type.
+ Byte(u8),
+ /// A D-Bus signed 16 bit type.
+ Int16(i16),
+ /// A D-Bus signed 32 bit type.
+ Int32(i32),
+ /// A D-Bus signed 64 bit type.
+ Int64(i64),
+ /// A D-Bus unsigned 16 bit type.
+ UInt16(u16),
+ /// A D-Bus unsigned 32 bit type.
+ UInt32(u32),
+ /// A D-Bus unsigned 64 bit type.
+ UInt64(u64),
+ /// A D-Bus IEEE-754 double-precision floating point type.
+ Double(f64),
+ /// D-Bus allows for sending file descriptors, which can be used to
+ /// set up SHM, unix pipes, or other communication channels.
+ UnixFd(OwnedFd),
+}
+
+fn iter_get_basic<T>(i: &mut ffi::DBusMessageIter) -> T {
+ unsafe {
+ let mut c: T = mem::zeroed();
+ let p = &mut c as *mut _ as *mut c_void;
+ ffi::dbus_message_iter_get_basic(i, p);
+ c
+ }
+}
+
+fn iter_append_array(i: &mut ffi::DBusMessageIter, a: &[MessageItem], t: &CStr) {
+ let mut subiter = new_dbus_message_iter();
+
+ assert!(unsafe { ffi::dbus_message_iter_open_container(i, ffi::DBUS_TYPE_ARRAY, t.as_ptr(), &mut subiter) } != 0);
+ for item in a.iter() {
+// assert!(item.type_sig() == t);
+ item.iter_append(&mut subiter);
+ }
+ assert!(unsafe { ffi::dbus_message_iter_close_container(i, &mut subiter) } != 0);
+}
+
+fn iter_append_struct(i: &mut ffi::DBusMessageIter, a: &[MessageItem]) {
+ let mut subiter = new_dbus_message_iter();
+ let res = unsafe { ffi::dbus_message_iter_open_container(i, ffi::DBUS_TYPE_STRUCT, ptr::null(), &mut subiter) };
+ assert!(res != 0);
+ for item in a.iter() {
+ item.iter_append(&mut subiter);
+ }
+ let res2 = unsafe { ffi::dbus_message_iter_close_container(i, &mut subiter) };
+ assert!(res2 != 0);
+}
+
+fn iter_append_variant(i: &mut ffi::DBusMessageIter, a: &MessageItem) {
+ let mut subiter = new_dbus_message_iter();
+ let asig = a.signature();
+ let atype = asig.as_cstr();
+ assert!(unsafe { ffi::dbus_message_iter_open_container(i, ffi::DBUS_TYPE_VARIANT, atype.as_ptr(), &mut subiter) } != 0);
+ a.iter_append(&mut subiter);
+ assert!(unsafe { ffi::dbus_message_iter_close_container(i, &mut subiter) } != 0);
+}
+
+fn iter_append_dict(i: &mut ffi::DBusMessageIter, k: &MessageItem, v: &MessageItem) {
+ let mut subiter = new_dbus_message_iter();
+ assert!(unsafe { ffi::dbus_message_iter_open_container(i, ffi::DBUS_TYPE_DICT_ENTRY, ptr::null(), &mut subiter) } != 0);
+ k.iter_append(&mut subiter);
+ v.iter_append(&mut subiter);
+ assert!(unsafe { ffi::dbus_message_iter_close_container(i, &mut subiter) } != 0);
+}
+
+impl MessageItem {
+ /// Get the D-Bus Signature for this MessageItem.
+ ///
+ /// Note: Since dictionary entries have no valid signature, calling this function for a dict entry will cause a panic.
+ pub fn signature(&self) -> Signature<'static> {
+ use arg::Variant;
+ match *self {
+ MessageItem::Str(_) => <String as Arg>::signature(),
+ MessageItem::Bool(_) => <bool as Arg>::signature(),
+ MessageItem::Byte(_) => <u8 as Arg>::signature(),
+ MessageItem::Int16(_) => <i16 as Arg>::signature(),
+ MessageItem::Int32(_) => <i32 as Arg>::signature(),
+ MessageItem::Int64(_) => <i64 as Arg>::signature(),
+ MessageItem::UInt16(_) => <u16 as Arg>::signature(),
+ MessageItem::UInt32(_) => <u32 as Arg>::signature(),
+ MessageItem::UInt64(_) => <u64 as Arg>::signature(),
+ MessageItem::Double(_) => <f64 as Arg>::signature(),
+ MessageItem::Array(ref a) => a.sig.clone(),
+ MessageItem::Struct(ref s) => Signature::new(format!("({})", s.iter().fold(String::new(), |s, i| s + &*i.signature()))).unwrap(),
+ MessageItem::Variant(_) => <Variant<u8> as Arg>::signature(),
+ MessageItem::DictEntry(_, _) => { panic!("Dict entries are only valid inside arrays, and therefore has no signature on their own") },
+ MessageItem::ObjectPath(_) => <Path as Arg>::signature(),
+ MessageItem::UnixFd(_) => <OwnedFd as Arg>::signature(),
+ }
+ }
+
+ /// Get the D-Bus ASCII type-code for this MessageItem.
+ #[deprecated(note="superseded by signature")]
+ #[allow(deprecated)]
+ pub fn type_sig(&self) -> super::TypeSig<'static> {
+ Cow::Owned(format!("{}", self.signature()))
+ }
+
+ /// Get the integer value for this MessageItem's type-code.
+ pub fn array_type(&self) -> i32 {
+ let s = match self {
+ &MessageItem::Str(_) => ffi::DBUS_TYPE_STRING,
+ &MessageItem::Bool(_) => ffi::DBUS_TYPE_BOOLEAN,
+ &MessageItem::Byte(_) => ffi::DBUS_TYPE_BYTE,
+ &MessageItem::Int16(_) => ffi::DBUS_TYPE_INT16,
+ &MessageItem::Int32(_) => ffi::DBUS_TYPE_INT32,
+ &MessageItem::Int64(_) => ffi::DBUS_TYPE_INT64,
+ &MessageItem::UInt16(_) => ffi::DBUS_TYPE_UINT16,
+ &MessageItem::UInt32(_) => ffi::DBUS_TYPE_UINT32,
+ &MessageItem::UInt64(_) => ffi::DBUS_TYPE_UINT64,
+ &MessageItem::Double(_) => ffi::DBUS_TYPE_DOUBLE,
+ &MessageItem::Array(_) => ffi::DBUS_TYPE_ARRAY,
+ &MessageItem::Struct(_) => ffi::DBUS_TYPE_STRUCT,
+ &MessageItem::Variant(_) => ffi::DBUS_TYPE_VARIANT,
+ &MessageItem::DictEntry(_,_) => ffi::DBUS_TYPE_DICT_ENTRY,
+ &MessageItem::ObjectPath(_) => ffi::DBUS_TYPE_OBJECT_PATH,
+ &MessageItem::UnixFd(_) => ffi::DBUS_TYPE_UNIX_FD,
+ };
+ s as i32
+ }
+
+ /// Creates a (String, Variant) dictionary from an iterator with Result passthrough (an Err will abort and return that Err)
+ pub fn from_dict<E, I: Iterator<Item=Result<(String, MessageItem),E>>>(i: I) -> Result<MessageItem, E> {
+ let mut v = Vec::new();
+ for r in i {
+ let (s, vv) = try!(r);
+ v.push((s.into(), Box::new(vv).into()).into());
+ }
+ Ok(MessageItem::Array(MessageItemArray::new(v, Signature::new("a{sv}").unwrap()).unwrap()))
+ }
+
+ /// Creates an MessageItem::Array from a list of MessageItems.
+ ///
+ /// Note: This requires `v` to be non-empty. See also
+ /// `MessageItem::from(&[T])`, which can handle empty arrays as well.
+ pub fn new_array(v: Vec<MessageItem>) -> Result<MessageItem,ArrayError> {
+ if v.len() == 0 {
+ return Err(ArrayError::EmptyArray);
+ }
+ let s = MessageItemArray::make_sig(&v[0]);
+ Ok(MessageItem::Array(MessageItemArray::new(v, s)?))
+ }
+
+
+ fn new_array2<D, I>(i: I) -> MessageItem
+ where D: Into<MessageItem>, D: Default, I: Iterator<Item=D> {
+ let v: Vec<MessageItem> = i.map(|ii| ii.into()).collect();
+ let s = {
+ let d;
+ let t = if v.len() == 0 { d = D::default().into(); &d } else { &v[0] };
+ MessageItemArray::make_sig(t)
+ };
+ MessageItem::Array(MessageItemArray::new(v, s).unwrap())
+ }
+
+ fn new_array3<'b, D: 'b, I>(i: I) -> MessageItem
+ where D: Into<MessageItem> + Default + Clone, I: Iterator<Item=&'b D> {
+ MessageItem::new_array2(i.map(|ii| ii.clone()))
+ }
+
+ fn from_iter_single(i: &mut ffi::DBusMessageIter) -> Option<MessageItem> {
+ let t = unsafe { ffi::dbus_message_iter_get_arg_type(i) };
+ match t {
+ ffi::DBUS_TYPE_INVALID => { None },
+ ffi::DBUS_TYPE_DICT_ENTRY => {
+ let mut subiter = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_recurse(i, &mut subiter) };
+ let a = MessageItem::from_iter(&mut subiter);
+ if a.len() != 2 { panic!("D-Bus dict entry error"); }
+ let mut a = a.into_iter();
+ let key = Box::new(a.next().unwrap());
+ let value = Box::new(a.next().unwrap());
+ Some(MessageItem::DictEntry(key, value))
+ }
+ ffi::DBUS_TYPE_VARIANT => {
+ let mut subiter = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_recurse(i, &mut subiter) };
+ let a = MessageItem::from_iter(&mut subiter);
+ if a.len() != 1 { panic!("D-Bus variant error"); }
+ Some(MessageItem::Variant(Box::new(a.into_iter().next().unwrap())))
+ }
+ ffi::DBUS_TYPE_ARRAY => {
+ let mut subiter = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_recurse(i, &mut subiter) };
+ let c = unsafe { ffi::dbus_message_iter_get_signature(&mut subiter) };
+ let s = format!("a{}", c_str_to_slice(&(c as *const c_char)).unwrap());
+ unsafe { ffi::dbus_free(c as *mut c_void) };
+ let t = Signature::new(s).unwrap();
+
+ let a = MessageItem::from_iter(&mut subiter);
+ Some(MessageItem::Array(MessageItemArray { v: a, sig: t }))
+ },
+ ffi::DBUS_TYPE_STRUCT => {
+ let mut subiter = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_recurse(i, &mut subiter) };
+ Some(MessageItem::Struct(MessageItem::from_iter(&mut subiter)))
+ },
+ ffi::DBUS_TYPE_STRING => {
+ let mut c: *const c_char = ptr::null();
+ unsafe {
+ let p: *mut c_void = mem::transmute(&mut c);
+ ffi::dbus_message_iter_get_basic(i, p);
+ };
+ Some(MessageItem::Str(c_str_to_slice(&c).expect("D-Bus string error").to_string()))
+ },
+ ffi::DBUS_TYPE_OBJECT_PATH => {
+ let mut c: *const c_char = ptr::null();
+ unsafe {
+ let p: *mut c_void = mem::transmute(&mut c);
+ ffi::dbus_message_iter_get_basic(i, p);
+ };
+ let o = Path::new(c_str_to_slice(&c).expect("D-Bus object path error")).ok().expect("D-Bus object path error");
+ Some(MessageItem::ObjectPath(o))
+ },
+ ffi::DBUS_TYPE_UNIX_FD => Some(MessageItem::UnixFd(OwnedFd::new(iter_get_basic(i)))),
+ ffi::DBUS_TYPE_BOOLEAN => Some(MessageItem::Bool(iter_get_basic::<u32>(i) != 0)),
+ ffi::DBUS_TYPE_BYTE => Some(MessageItem::Byte(iter_get_basic(i))),
+ ffi::DBUS_TYPE_INT16 => Some(MessageItem::Int16(iter_get_basic(i))),
+ ffi::DBUS_TYPE_INT32 => Some(MessageItem::Int32(iter_get_basic(i))),
+ ffi::DBUS_TYPE_INT64 => Some(MessageItem::Int64(iter_get_basic(i))),
+ ffi::DBUS_TYPE_UINT16 => Some(MessageItem::UInt16(iter_get_basic(i))),
+ ffi::DBUS_TYPE_UINT32 => Some(MessageItem::UInt32(iter_get_basic(i))),
+ ffi::DBUS_TYPE_UINT64 => Some(MessageItem::UInt64(iter_get_basic(i))),
+ ffi::DBUS_TYPE_DOUBLE => Some(MessageItem::Double(iter_get_basic(i))),
+ _ => { None /* Only the new msgarg module supports signatures */ }
+ }
+ }
+
+ fn from_iter(i: &mut ffi::DBusMessageIter) -> Vec<MessageItem> {
+ let mut v = Vec::new();
+ while let Some(m) = Self::from_iter_single(i) {
+ v.push(m);
+ unsafe { ffi::dbus_message_iter_next(i) };
+ }
+ v
+ }
+
+ fn iter_append_basic<T>(&self, i: &mut ffi::DBusMessageIter, v: T) {
+ let t = self.array_type() as c_int;
+ let p = &v as *const _ as *const c_void;
+ unsafe {
+ ffi::dbus_message_iter_append_basic(i, t, p);
+ }
+ }
+
+ fn iter_append(&self, i: &mut ffi::DBusMessageIter) {
+ match self {
+ &MessageItem::Str(ref s) => unsafe {
+ let c = to_c_str(s);
+ let p = mem::transmute(&c);
+ ffi::dbus_message_iter_append_basic(i, ffi::DBUS_TYPE_STRING, p);
+ },
+ &MessageItem::Bool(b) => self.iter_append_basic(i, if b { 1u32 } else { 0u32 }),
+ &MessageItem::Byte(b) => self.iter_append_basic(i, b),
+ &MessageItem::Int16(b) => self.iter_append_basic(i, b),
+ &MessageItem::Int32(b) => self.iter_append_basic(i, b),
+ &MessageItem::Int64(b) => self.iter_append_basic(i, b),
+ &MessageItem::UInt16(b) => self.iter_append_basic(i, b),
+ &MessageItem::UInt32(b) => self.iter_append_basic(i, b),
+ &MessageItem::UInt64(b) => self.iter_append_basic(i, b),
+ &MessageItem::UnixFd(ref b) => self.iter_append_basic(i, b.as_raw_fd()),
+ &MessageItem::Double(b) => self.iter_append_basic(i, b),
+ &MessageItem::Array(ref a) => iter_append_array(i, &a.v, a.element_signature()),
+ &MessageItem::Struct(ref v) => iter_append_struct(i, &**v),
+ &MessageItem::Variant(ref b) => iter_append_variant(i, &**b),
+ &MessageItem::DictEntry(ref k, ref v) => iter_append_dict(i, &**k, &**v),
+ &MessageItem::ObjectPath(ref s) => unsafe {
+ let c: *const libc::c_char = s.as_ref().as_ptr();
+ let p = mem::transmute(&c);
+ ffi::dbus_message_iter_append_basic(i, ffi::DBUS_TYPE_OBJECT_PATH, p);
+ }
+ }
+ }
+
+ fn copy_to_iter(i: &mut ffi::DBusMessageIter, v: &[MessageItem]) {
+ for item in v.iter() {
+ item.iter_append(i);
+ }
+ }
+
+ /// Conveniently get the inner value of a `MessageItem`
+ ///
+ /// # Example
+ /// ```
+ /// use dbus::MessageItem;
+ /// let m: MessageItem = 5i64.into();
+ /// let s: i64 = m.inner().unwrap();
+ /// assert_eq!(s, 5i64);
+ /// ```
+ pub fn inner<'a, T: FromMessageItem<'a>>(&'a self) -> Result<T, ()> {
+ T::from(self)
+ }
+}
+
+
+// For use by the msgarg module
+pub fn append_messageitem(i: &mut ffi::DBusMessageIter, m: &MessageItem) {
+ m.iter_append(i)
+}
+
+// For use by the msgarg module
+pub fn get_messageitem(i: &mut ffi::DBusMessageIter) -> Option<MessageItem> {
+ MessageItem::from_iter_single(i)
+}
+
+
+macro_rules! msgitem_convert {
+ ($t: ty, $s: ident) => {
+ impl From<$t> for MessageItem { fn from(i: $t) -> MessageItem { MessageItem::$s(i) } }
+
+ impl<'a> FromMessageItem<'a> for $t {
+ fn from(i: &'a MessageItem) -> Result<$t,()> {
+ if let &MessageItem::$s(ref b) = i { Ok(*b) } else { Err(()) }
+ }
+ }
+ }
+}
+
+msgitem_convert!(u8, Byte);
+msgitem_convert!(u64, UInt64);
+msgitem_convert!(u32, UInt32);
+msgitem_convert!(u16, UInt16);
+msgitem_convert!(i16, Int16);
+msgitem_convert!(i32, Int32);
+msgitem_convert!(i64, Int64);
+msgitem_convert!(f64, Double);
+msgitem_convert!(bool, Bool);
+
+
+/// Create a `MessageItem::Array`.
+impl<'a, T> From<&'a [T]> for MessageItem
+where T: Into<MessageItem> + Clone + Default {
+ fn from(i: &'a [T]) -> MessageItem {
+ MessageItem::new_array3(i.iter())
+ }
+}
+
+impl<'a> From<&'a str> for MessageItem { fn from(i: &str) -> MessageItem { MessageItem::Str(i.to_string()) } }
+
+impl From<String> for MessageItem { fn from(i: String) -> MessageItem { MessageItem::Str(i) } }
+
+impl From<Path<'static>> for MessageItem { fn from(i: Path<'static>) -> MessageItem { MessageItem::ObjectPath(i) } }
+
+impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(i) } }
+
+/// Create a `MessageItem::Variant`
+impl From<Box<MessageItem>> for MessageItem {
+ fn from(i: Box<MessageItem>) -> MessageItem { MessageItem::Variant(i) }
+}
+
+/// Create a `MessageItem::DictEntry`
+impl From<(MessageItem, MessageItem)> for MessageItem {
+ fn from(i: (MessageItem, MessageItem)) -> MessageItem {
+ MessageItem::DictEntry(Box::new(i.0), Box::new(i.1))
+ }
+}
+
+/// Helper trait for `MessageItem::inner()`
+pub trait FromMessageItem<'a> :Sized {
+ /// Allows converting from a MessageItem into the type it contains.
+ fn from(i: &'a MessageItem) -> Result<Self, ()>;
+}
+
+impl<'a> FromMessageItem<'a> for &'a str {
+ fn from(i: &'a MessageItem) -> Result<&'a str,()> {
+ match i {
+ &MessageItem::Str(ref b) => Ok(&b),
+ &MessageItem::ObjectPath(ref b) => Ok(&b),
+ _ => Err(()),
+ }
+ }
+}
+
+impl<'a> FromMessageItem<'a> for &'a String {
+ fn from(i: &'a MessageItem) -> Result<&'a String,()> { if let &MessageItem::Str(ref b) = i { Ok(&b) } else { Err(()) } }
+}
+
+impl<'a> FromMessageItem<'a> for &'a Path<'static> {
+ fn from(i: &'a MessageItem) -> Result<&'a Path<'static>,()> { if let &MessageItem::ObjectPath(ref b) = i { Ok(&b) } else { Err(()) } }
+}
+
+impl<'a> FromMessageItem<'a> for &'a MessageItem {
+ fn from(i: &'a MessageItem) -> Result<&'a MessageItem,()> { if let &MessageItem::Variant(ref b) = i { Ok(&**b) } else { Err(()) } }
+}
+
+impl<'a> FromMessageItem<'a> for &'a Vec<MessageItem> {
+ fn from(i: &'a MessageItem) -> Result<&'a Vec<MessageItem>,()> {
+ match i {
+ &MessageItem::Array(ref b) => Ok(&b.v),
+ &MessageItem::Struct(ref b) => Ok(&b),
+ _ => Err(()),
+ }
+ }
+}
+
+impl<'a> FromMessageItem<'a> for &'a [MessageItem] {
+ fn from(i: &'a MessageItem) -> Result<&'a [MessageItem],()> { i.inner::<&Vec<MessageItem>>().map(|s| &**s) }
+}
+
+impl<'a> FromMessageItem<'a> for &'a OwnedFd {
+ fn from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let &MessageItem::UnixFd(ref b) = i { Ok(b) } else { Err(()) } }
+}
+
+impl<'a> FromMessageItem<'a> for (&'a MessageItem, &'a MessageItem) {
+ fn from(i: &'a MessageItem) -> Result<(&'a MessageItem, &'a MessageItem),()> {
+ if let &MessageItem::DictEntry(ref k, ref v) = i { Ok((&**k, &**v)) } else { Err(()) }
+ }
+}
+
+
+/// A D-Bus message. A message contains some headers (e g sender and destination address)
+/// and a list of MessageItems.
+pub struct Message {
+ msg: *mut ffi::DBusMessage,
+}
+
+unsafe impl Send for Message {}
+
+impl Message {
+ /// Creates a new method call message.
+ pub fn new_method_call<'d, 'p, 'i, 'm, D, P, I, M>(destination: D, path: P, iface: I, method: M) -> Result<Message, String>
+ where D: Into<BusName<'d>>, P: Into<Path<'p>>, I: Into<Interface<'i>>, M: Into<Member<'m>> {
+ init_dbus();
+ let (d, p, i, m) = (destination.into(), path.into(), iface.into(), method.into());
+ let ptr = unsafe {
+ ffi::dbus_message_new_method_call(d.as_ref().as_ptr(), p.as_ref().as_ptr(), i.as_ref().as_ptr(), m.as_ref().as_ptr())
+ };
+ if ptr == ptr::null_mut() { Err("D-Bus error: dbus_message_new_method_call failed".into()) }
+ else { Ok(Message { msg: ptr}) }
+ }
+
+ /// Creates a new method call message.
+ pub fn method_call(destination: &BusName, path: &Path, iface: &Interface, name: &Member) -> Message {
+ init_dbus();
+ let ptr = unsafe {
+ ffi::dbus_message_new_method_call(destination.as_ref().as_ptr(), path.as_ref().as_ptr(),
+ iface.as_ref().as_ptr(), name.as_ref().as_ptr())
+ };
+ if ptr == ptr::null_mut() { panic!("D-Bus error: dbus_message_new_signal failed") }
+ Message { msg: ptr}
+ }
+
+ /// Creates a new signal message.
+ pub fn new_signal<P, I, M>(path: P, iface: I, name: M) -> Result<Message, String>
+ where P: Into<Vec<u8>>, I: Into<Vec<u8>>, M: Into<Vec<u8>> {
+ init_dbus();
+
+ let p = try!(Path::new(path));
+ let i = try!(Interface::new(iface));
+ let m = try!(Member::new(name));
+
+ let ptr = unsafe {
+ ffi::dbus_message_new_signal(p.as_ref().as_ptr(), i.as_ref().as_ptr(), m.as_ref().as_ptr())
+ };
+ if ptr == ptr::null_mut() { Err("D-Bus error: dbus_message_new_signal failed".into()) }
+ else { Ok(Message { msg: ptr}) }
+ }
+
+ /// Creates a new signal message.
+ pub fn signal(path: &Path, iface: &Interface, name: &Member) -> Message {
+ init_dbus();
+ let ptr = unsafe {
+ ffi::dbus_message_new_signal(path.as_ref().as_ptr(), iface.as_ref().as_ptr(), name.as_ref().as_ptr())
+ };
+ if ptr == ptr::null_mut() { panic!("D-Bus error: dbus_message_new_signal failed") }
+ Message { msg: ptr}
+ }
+
+ /// Creates a method reply for this method call.
+ pub fn new_method_return(m: &Message) -> Option<Message> {
+ let ptr = unsafe { ffi::dbus_message_new_method_return(m.msg) };
+ if ptr == ptr::null_mut() { None } else { Some(Message { msg: ptr} ) }
+ }
+
+ /// Creates a method return (reply) for this method call.
+ pub fn method_return(&self) -> Message {
+ let ptr = unsafe { ffi::dbus_message_new_method_return(self.msg) };
+ if ptr == ptr::null_mut() { panic!("D-Bus error: dbus_message_new_method_return failed") }
+ Message {msg: ptr}
+ }
+
+ /// The old way to create a new error reply
+ pub fn new_error(m: &Message, error_name: &str, error_message: &str) -> Option<Message> {
+ let (en, em) = (to_c_str(error_name), to_c_str(error_message));
+ let ptr = unsafe { ffi::dbus_message_new_error(m.msg, en.as_ptr(), em.as_ptr()) };
+ if ptr == ptr::null_mut() { None } else { Some(Message { msg: ptr} ) }
+ }
+
+ /// Creates a new error reply
+ pub fn error(&self, error_name: &ErrorName, error_message: &CStr) -> Message {
+ let ptr = unsafe { ffi::dbus_message_new_error(self.msg, error_name.as_ref().as_ptr(), error_message.as_ptr()) };
+ if ptr == ptr::null_mut() { panic!("D-Bus error: dbus_message_new_error failed") }
+ Message { msg: ptr}
+ }
+
+ /// Get the MessageItems that make up the message.
+ ///
+ /// Note: use `iter_init` or `get1`/`get2`/etc instead for faster access to the arguments.
+ /// This method is provided for backwards compatibility.
+ pub fn get_items(&self) -> Vec<MessageItem> {
+ let mut i = new_dbus_message_iter();
+ match unsafe { ffi::dbus_message_iter_init(self.msg, &mut i) } {
+ 0 => Vec::new(),
+ _ => MessageItem::from_iter(&mut i)
+ }
+ }
+
+ /// Get the D-Bus serial of a message, if one was specified.
+ pub fn get_serial(&self) -> u32 {
+ unsafe { ffi::dbus_message_get_serial(self.msg) }
+ }
+
+ /// Get the serial of the message this message is a reply to, if present.
+ pub fn get_reply_serial(&self) -> Option<u32> {
+ let s = unsafe { ffi::dbus_message_get_reply_serial(self.msg) };
+ if s == 0 { None } else { Some(s) }
+ }
+
+ /// Returns true if the message does not expect a reply.
+ pub fn get_no_reply(&self) -> bool { unsafe { ffi::dbus_message_get_no_reply(self.msg) != 0 } }
+
+ /// Set whether or not the message expects a reply.
+ ///
+ /// Set to true if you send a method call and do not want a reply.
+ pub fn set_no_reply(&self, v: bool) {
+ unsafe { ffi::dbus_message_set_no_reply(self.msg, if v { 1 } else { 0 }) }
+ }
+
+ /// Returns true if the message can cause a service to be auto-started.
+ pub fn get_auto_start(&self) -> bool { unsafe { ffi::dbus_message_get_auto_start(self.msg) != 0 } }
+
+ /// Sets whether or not the message can cause a service to be auto-started.
+ ///
+ /// Defaults to true.
+ pub fn set_auto_start(&self, v: bool) {
+ unsafe { ffi::dbus_message_set_auto_start(self.msg, if v { 1 } else { 0 }) }
+ }
+
+ /// Add one or more MessageItems to this Message.
+ ///
+ /// Note: using `append1`, `append2` or `append3` might be faster, especially for large arrays.
+ /// This method is provided for backwards compatibility.
+ pub fn append_items(&mut self, v: &[MessageItem]) {
+ let mut i = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_init_append(self.msg, &mut i) };
+ MessageItem::copy_to_iter(&mut i, v);
+ }
+
+ /// Appends one MessageItem to a message.
+ /// Use in builder style: e g `m.method_return().append(7i32)`
+ ///
+ /// Note: using `append1`, `append2` or `append3` might be faster, especially for large arrays.
+ /// This method is provided for backwards compatibility.
+ pub fn append<I: Into<MessageItem>>(self, v: I) -> Self {
+ let mut i = new_dbus_message_iter();
+ unsafe { ffi::dbus_message_iter_init_append(self.msg, &mut i) };
+ MessageItem::copy_to_iter(&mut i, &[v.into()]);
+ self
+ }
+
+ /// Appends one argument to this message.
+ /// Use in builder style: e g `m.method_return().append1(7i32)`
+ pub fn append1<A: Append>(mut self, a: A) -> Self {
+ {
+ let mut m = IterAppend::new(&mut self);
+ m.append(a);
+ }
+ self
+ }
+
+ /// Appends two arguments to this message.
+ /// Use in builder style: e g `m.method_return().append2(7i32, 6u8)`
+ pub fn append2<A1: Append, A2: Append>(mut self, a1: A1, a2: A2) -> Self {
+ {
+ let mut m = IterAppend::new(&mut self);
+ m.append(a1); m.append(a2);
+ }
+ self
+ }
+
+ /// Appends three arguments to this message.
+ /// Use in builder style: e g `m.method_return().append3(7i32, 6u8, true)`
+ pub fn append3<A1: Append, A2: Append, A3: Append>(mut self, a1: A1, a2: A2, a3: A3) -> Self {
+ {
+ let mut m = IterAppend::new(&mut self);
+ m.append(a1); m.append(a2); m.append(a3);
+ }
+ self
+ }
+
+ /// Appends RefArgs to this message.
+ /// Use in builder style: e g `m.method_return().append_ref(&[7i32, 6u8, true])`
+ pub fn append_ref<A: RefArg>(mut self, r: &[A]) -> Self {
+ {
+ let mut m = IterAppend::new(&mut self);
+ for rr in r {
+ rr.append(&mut m);
+ }
+ }
+ self
+ }
+
+ /// Gets the first argument from the message, if that argument is of type G1.
+ /// Returns None if there are not enough arguments, or if types don't match.
+ pub fn get1<'a, G1: Get<'a>>(&'a self) -> Option<G1> {
+ let mut i = Iter::new(&self);
+ i.get()
+ }
+
+ /// Gets the first two arguments from the message, if those arguments are of type G1 and G2.
+ /// Returns None if there are not enough arguments, or if types don't match.
+ pub fn get2<'a, G1: Get<'a>, G2: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>) {
+ let mut i = Iter::new(&self);
+ let g1 = i.get();
+ if !i.next() { return (g1, None); }
+ (g1, i.get())
+ }
+
+ /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3.
+ /// Returns None if there are not enough arguments, or if types don't match.
+ pub fn get3<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>) {
+ let mut i = Iter::new(&self);
+ let g1 = i.get();
+ if !i.next() { return (g1, None, None) }
+ let g2 = i.get();
+ if !i.next() { return (g1, g2, None) }
+ (g1, g2, i.get())
+ }
+
+ /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4.
+ /// Returns None if there are not enough arguments, or if types don't match.
+ pub fn get4<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>) {
+ let mut i = Iter::new(&self);
+ let g1 = i.get();
+ if !i.next() { return (g1, None, None, None) }
+ let g2 = i.get();
+ if !i.next() { return (g1, g2, None, None) }
+ let g3 = i.get();
+ if !i.next() { return (g1, g2, g3, None) }
+ (g1, g2, g3, i.get())
+ }
+
+ /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3 and G4.
+ /// Returns None if there are not enough arguments, or if types don't match.
+ /// Note: If you need more than five arguments, use `iter_init` instead.
+ pub fn get5<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>, G5: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>, Option<G5>) {
+ let mut i = Iter::new(&self);
+ let g1 = i.get();
+ if !i.next() { return (g1, None, None, None, None) }
+ let g2 = i.get();
+ if !i.next() { return (g1, g2, None, None, None) }
+ let g3 = i.get();
+ if !i.next() { return (g1, g2, g3, None, None) }
+ let g4 = i.get();
+ if !i.next() { return (g1, g2, g3, g4, None) }
+ (g1, g2, g3, g4, i.get())
+ }
+
+ /// Gets the first argument from the message, if that argument is of type G1.
+ ///
+ /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
+ pub fn read1<'a, G1: Arg + Get<'a>>(&'a self) -> Result<G1, TypeMismatchError> {
+ let mut i = Iter::new(&self);
+ i.read()
+ }
+
+ /// Gets the first two arguments from the message, if those arguments are of type G1 and G2.
+ ///
+ /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
+ pub fn read2<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>>(&'a self) -> Result<(G1, G2), TypeMismatchError> {
+ let mut i = Iter::new(&self);
+ Ok((try!(i.read()), try!(i.read())))
+ }
+
+ /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3.
+ ///
+ /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
+ pub fn read3<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>>(&'a self) ->
+ Result<(G1, G2, G3), TypeMismatchError> {
+ let mut i = Iter::new(&self);
+ Ok((try!(i.read()), try!(i.read()), try!(i.read())))
+ }
+
+ /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4.
+ ///
+ /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
+ pub fn read4<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>>(&'a self) ->
+ Result<(G1, G2, G3, G4), TypeMismatchError> {
+ let mut i = Iter::new(&self);
+ Ok((try!(i.read()), try!(i.read()), try!(i.read()), try!(i.read())))
+ }
+
+ /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3, G4 and G5.
+ ///
+ /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
+ /// Note: If you need more than five arguments, use `iter_init` instead.
+ pub fn read5<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>, G5: Arg + Get<'a>>(&'a self) ->
+ Result<(G1, G2, G3, G4, G5), TypeMismatchError> {
+ let mut i = Iter::new(&self);
+ Ok((try!(i.read()), try!(i.read()), try!(i.read()), try!(i.read()), try!(i.read())))
+ }
+
+ /// Returns a struct for retreiving the arguments from a message. Supersedes get_items().
+ pub fn iter_init<'a>(&'a self) -> Iter<'a> { Iter::new(&self) }
+
+ /// Gets the MessageType of the Message.
+ pub fn msg_type(&self) -> MessageType {
+ unsafe { mem::transmute(ffi::dbus_message_get_type(self.msg)) }
+ }
+
+ fn msg_internal_str<'a>(&'a self, c: *const libc::c_char) -> Option<&'a [u8]> {
+ if c == ptr::null() { None }
+ else { Some( unsafe { CStr::from_ptr(c) }.to_bytes_with_nul()) }
+ }
+
+ /// Gets the name of the connection that originated this message.
+ pub fn sender<'a>(&'a self) -> Option<BusName<'a>> {
+ self.msg_internal_str(unsafe { ffi::dbus_message_get_sender(self.msg) })
+ .map(|s| unsafe { BusName::from_slice_unchecked(s) })
+ }
+
+ /// Returns a tuple of (Message type, Path, Interface, Member) of the current message.
+ pub fn headers(&self) -> (MessageType, Option<String>, Option<String>, Option<String>) {
+ let p = unsafe { ffi::dbus_message_get_path(self.msg) };
+ let i = unsafe { ffi::dbus_message_get_interface(self.msg) };
+ let m = unsafe { ffi::dbus_message_get_member(self.msg) };
+ (self.msg_type(),
+ c_str_to_slice(&p).map(|s| s.to_string()),
+ c_str_to_slice(&i).map(|s| s.to_string()),
+ c_str_to_slice(&m).map(|s| s.to_string()))
+ }
+
+ /// Gets the object path this Message is being sent to.
+ pub fn path<'a>(&'a self) -> Option<Path<'a>> {
+ self.msg_internal_str(unsafe { ffi::dbus_message_get_path(self.msg) })
+ .map(|s| unsafe { Path::from_slice_unchecked(s) })
+ }
+
+ /// Gets the destination this Message is being sent to.
+ pub fn destination<'a>(&'a self) -> Option<BusName<'a>> {
+ self.msg_internal_str(unsafe { ffi::dbus_message_get_destination(self.msg) })
+ .map(|s| unsafe { BusName::from_slice_unchecked(s) })
+ }
+
+ /// Sets the destination of this Message
+ ///
+ /// If dest is none, that means broadcast to all relevant destinations.
+ pub fn set_destination(&mut self, dest: Option<BusName>) {
+ let c_dest = dest.as_ref().map(|d| d.as_cstr().as_ptr()).unwrap_or(ptr::null());
+ assert!(unsafe { ffi::dbus_message_set_destination(self.msg, c_dest) } != 0);
+ }
+
+ /// Gets the interface this Message is being sent to.
+ pub fn interface<'a>(&'a self) -> Option<Interface<'a>> {
+ self.msg_internal_str(unsafe { ffi::dbus_message_get_interface(self.msg) })
+ .map(|s| unsafe { Interface::from_slice_unchecked(s) })
+ }
+
+ /// Gets the interface member being called.
+ pub fn member<'a>(&'a self) -> Option<Member<'a>> {
+ self.msg_internal_str(unsafe { ffi::dbus_message_get_member(self.msg) })
+ .map(|s| unsafe { Member::from_slice_unchecked(s) })
+ }
+
+ /// When the remote end returns an error, the message itself is
+ /// correct but its contents is an error. This method will
+ /// transform such an error to a D-Bus Error or otherwise return
+ /// the original message.
+ pub fn as_result(&mut self) -> Result<&mut Message, Error> {
+ self.set_error_from_msg().map(|_| self)
+ }
+
+ pub (super) fn set_error_from_msg(&self) -> Result<(), Error> {
+ let mut e = Error::empty();
+ if unsafe { ffi::dbus_set_error_from_message(e.get_mut(), self.msg) } != 0 { Err(e) }
+ else { Ok(()) }
+ }
+
+ pub (crate) fn ptr(&self) -> *mut ffi::DBusMessage { self.msg }
+
+ pub (crate) fn from_ptr(ptr: *mut ffi::DBusMessage, add_ref: bool) -> Message {
+ if add_ref {
+ unsafe { ffi::dbus_message_ref(ptr) };
+ }
+ Message { msg: ptr }
+ }
+
+}
+
+impl Drop for Message {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::dbus_message_unref(self.msg);
+ }
+ }
+}
+
+impl fmt::Debug for Message {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(f, "{:?}", self.headers())
+ }
+}
+
+/// A convenience struct that wraps connection, destination and path.
+///
+/// Useful if you want to make many method calls to the same destination path.
+#[derive(Clone, Debug)]
+pub struct ConnPath<'a, C> {
+ /// Some way to access the connection, e g a &Connection or Rc<Connection>
+ pub conn: C,
+ /// Destination, i e what D-Bus service you're communicating with
+ pub dest: BusName<'a>,
+ /// Object path on the destination
+ pub path: Path<'a>,
+ /// Timeout in milliseconds for blocking method calls
+ pub timeout: i32,
+}
+
+impl<'a, C: ::std::ops::Deref<Target=Connection>> ConnPath<'a, C> {
+ /// Make a D-Bus method call, where you can append arguments inside the closure.
+ pub fn method_call_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<Message, Error> {
+ let mut msg = Message::method_call(&self.dest, &self.path, i, m);
+ f(&mut msg);
+ self.conn.send_with_reply_and_block(msg, self.timeout)
+ }
+
+ /// Emit a D-Bus signal, where you can append arguments inside the closure.
+ pub fn signal_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<u32, Error> {
+ let mut msg = Message::signal(&self.path, i, m);
+ f(&mut msg);
+ self.conn.send(msg).map_err(|_| Error::new_custom("org.freedesktop.DBus.Error.Failed", "Sending signal failed"))
+ }
+
+ /// Emit a D-Bus signal, where the arguments are in a struct.
+ pub fn emit<S: SignalArgs>(&self, signal: &S) -> Result<u32, Error> {
+ let msg = signal.to_emit_message(&self.path);
+ self.conn.send(msg).map_err(|_| Error::new_custom("org.freedesktop.DBus.Error.Failed", "Sending signal failed"))
+ }
+}
+
+// For purpose of testing the library only.
+#[cfg(test)]
+pub (crate) fn message_set_serial(m: &mut Message, s: u32) {
+ unsafe { ffi::dbus_message_set_serial(m.msg, s) };
+}
+
+#[cfg(test)]
+mod test {
+ extern crate tempdir;
+
+ use super::super::{Connection, Message, MessageType, BusType, MessageItem, OwnedFd, libc, Path, BusName};
+
+ #[test]
+ fn unix_fd() {
+ use std::io::prelude::*;
+ use std::io::SeekFrom;
+ use std::fs::OpenOptions;
+ use std::os::unix::io::AsRawFd;
+
+ let c = Connection::get_private(BusType::Session).unwrap();
+ c.register_object_path("/hello").unwrap();
+ let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
+ let tempdir = tempdir::TempDir::new("dbus-rs-test").unwrap();
+ let mut filename = tempdir.path().to_path_buf();
+ filename.push("test");
+ println!("Creating file {:?}", filename);
+ let mut file = OpenOptions::new().create(true).read(true).write(true).open(&filename).unwrap();
+ file.write_all(b"z").unwrap();
+ file.seek(SeekFrom::Start(0)).unwrap();
+ let ofd = OwnedFd::new(file.as_raw_fd());
+ m.append_items(&[MessageItem::UnixFd(ofd.clone())]);
+ println!("Sending {:?}", m.get_items());
+ c.send(m).unwrap();
+
+ loop { for n in c.incoming(1000) {
+ if n.msg_type() == MessageType::MethodCall {
+ let z: OwnedFd = n.read1().unwrap();
+ println!("Got {:?}", z);
+ let mut q: libc::c_char = 100;
+ assert_eq!(1, unsafe { libc::read(z.as_raw_fd(), &mut q as *mut _ as *mut libc::c_void, 1) });
+ assert_eq!(q, 'z' as libc::c_char);
+ return;
+ } else {
+ println!("Got {:?}", n);
+ }
+ }}
+ }
+
+ #[test]
+ fn message_types() {
+ let c = Connection::get_private(BusType::Session).unwrap();
+ c.register_object_path("/hello").unwrap();
+ let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
+ m.append_items(&[
+ 2000u16.into(),
+ MessageItem::new_array(vec!(129u8.into())).unwrap(),
+ ["Hello", "world"][..].into(),
+ 987654321u64.into(),
+ (-1i32).into(),
+ format!("Hello world").into(),
+ (-3.14f64).into(),
+ MessageItem::Struct(vec!(256i16.into())),
+ Path::new("/some/path").unwrap().into(),
+ MessageItem::new_array(vec!((123543u32.into(), true.into()).into())).unwrap()
+ ]);
+ let sending = format!("{:?}", m.get_items());
+ println!("Sending {}", sending);
+ c.send(m).unwrap();
+
+ loop { for n in c.incoming(1000) {
+ if n.msg_type() == MessageType::MethodCall {
+ let receiving = format!("{:?}", n.get_items());
+ println!("Receiving {}", receiving);
+ assert_eq!(sending, receiving);
+ return;
+ } else {
+ println!("Got {:?}", n);
+ }
+ }}
+ }
+
+ #[test]
+ fn dict_of_dicts() {
+ use std::collections::BTreeMap;
+
+ let officeactions: BTreeMap<&'static str, MessageItem> = BTreeMap::new();
+ let mut officethings = BTreeMap::new();
+ officethings.insert("pencil", 2u16.into());
+ officethings.insert("paper", 5u16.into());
+ let mut homethings = BTreeMap::new();
+ homethings.insert("apple", 11u16.into());
+ let mut homeifaces = BTreeMap::new();
+ homeifaces.insert("getThings", homethings);
+ let mut officeifaces = BTreeMap::new();
+ officeifaces.insert("getThings", officethings);
+ officeifaces.insert("getActions", officeactions);
+ let mut paths = BTreeMap::new();
+ paths.insert("/hello/office", officeifaces);
+ paths.insert("/hello/home", homeifaces);
+
+ println!("Original treemap: {:?}", paths);
+ let m = MessageItem::new_array(paths.iter().map(
+ |(path, ifaces)| (MessageItem::ObjectPath(Path::new(*path).unwrap()),
+ MessageItem::new_array(ifaces.iter().map(
+ |(iface, props)| (iface.to_string().into(),
+ MessageItem::from_dict::<(),_>(props.iter().map(
+ |(name, value)| Ok((name.to_string(), value.clone()))
+ )).unwrap()
+ ).into()
+ ).collect()).unwrap()
+ ).into()
+ ).collect()).unwrap();
+ println!("As MessageItem: {:?}", m);
+ assert_eq!(&*m.signature(), "a{oa{sa{sv}}}");
+
+ let c = Connection::get_private(BusType::Session).unwrap();
+ c.register_object_path("/hello").unwrap();
+ let mut msg = Message::new_method_call(&c.unique_name(), "/hello", "org.freedesktop.DBusObjectManager", "GetManagedObjects").unwrap();
+ msg.append_items(&[m]);
+ let sending = format!("{:?}", msg.get_items());
+ println!("Sending {}", sending);
+ c.send(msg).unwrap();
+
+ loop { for n in c.incoming(1000) {
+ if n.msg_type() == MessageType::MethodCall {
+ let receiving = format!("{:?}", n.get_items());
+ println!("Receiving {}", receiving);
+ assert_eq!(sending, receiving);
+ return;
+ } else {
+ println!("Got {:?}", n);
+ }
+ } }
+ }
+
+ #[test]
+ fn issue24() {
+ let c = Connection::get_private(BusType::Session).unwrap();
+ let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap();
+
+ let a = MessageItem::from("test".to_string());
+ let b = MessageItem::from("test".to_string());
+ let foo = MessageItem::Struct(vec!(a, b));
+ let bar = foo.clone();
+
+ let args = [MessageItem::new_array(vec!(foo, bar)).unwrap()];
+ println!("{:?}", args);
+
+ m.append_items(&args);
+ c.send(m).unwrap();
+ }
+
+ #[test]
+ fn set_valid_destination() {
+ let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap();
+ let d = Some(BusName::new(":1.14").unwrap());
+ m.set_destination(d);
+
+ assert!(!m.get_no_reply());
+ m.set_no_reply(true);
+ assert!(m.get_no_reply());
+ }
+}
diff --git a/third_party/rust/dbus/src/methoddisp.rs b/third_party/rust/dbus/src/methoddisp.rs
new file mode 100644
index 0000000000..9f3ed3695b
--- /dev/null
+++ b/third_party/rust/dbus/src/methoddisp.rs
@@ -0,0 +1,1058 @@
+/// NOTE: No longer used - replaced with files in the "tree" directory.
+
+
+#![allow(dead_code)]
+
+use {MessageItem, Message, MessageType, Connection, ConnectionItem, Error, ErrorName};
+use {Signature, Member, Path};
+use Interface as IfaceName;
+use std::cell::RefCell;
+use std::sync::{Arc, Mutex};
+use std::collections::BTreeMap;
+use std::marker::PhantomData;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use super::arg;
+
+type ArcMap<K, V> = BTreeMap<Arc<K>, Arc<V>>;
+
+#[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) }
+
+ 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)
+ }
+ fn introspect_all(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)]
+struct Annotations(Option<BTreeMap<String, String>>);
+
+impl Annotations {
+ fn new() -> Annotations { Annotations(None) }
+
+ 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());
+ }
+
+ 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()) }
+}
+
+#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+/// A D-Bus Method Error.
+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 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()
+ }
+}
+
+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()) }
+}
+
+/// Result containing the Messages returned from the Method, or a MethodErr.
+pub type MethodResult = Result<Vec<Message>, MethodErr>;
+
+/// A MethodType that wraps an Fn function
+pub struct MethodFn<'a>(Box<Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + 'a>);
+/// A MethodType that wraps an FnMut function. Calling this recursively will cause a refcell panic.
+pub struct MethodFnMut<'a>(Box<RefCell<FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + 'a>>);
+/// A MethodType that wraps an Fn+Send+Sync function, so it can be called from several threads in parallel.
+pub struct MethodSync(Box<Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static>);
+
+impl<'a> fmt::Debug for MethodFn<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Fn>") }
+}
+
+impl<'a> fmt::Debug for MethodFnMut<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<FnMut>") }
+}
+
+impl fmt::Debug for MethodSync {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Fn + Send + Sync>") }
+}
+
+/// A helper trait used internally to make the tree generic over MethodFn, MethodFnMut and MethodSync.
+pub trait MethodType: Sized {
+ fn call_method(&self, m: &Message, o: &ObjectPath<Self>, i: &Tree<Self>) -> MethodResult;
+ fn box_method<H>(h: H) -> Self
+ where H: Fn(&Message, &ObjectPath<Self>, &Tree<Self>) -> MethodResult + Send + Sync + 'static;
+}
+
+impl<'a> MethodType for MethodFn<'a> {
+ fn call_method(&self, m: &Message, o: &ObjectPath<MethodFn<'a>>, i: &Tree<MethodFn<'a>>) -> MethodResult { self.0(m, o, i) }
+
+ fn box_method<H>(h: H) -> Self
+ where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + Send + Sync + 'static {
+ MethodFn(Box::new(h))
+ }
+}
+
+impl MethodType for MethodSync {
+ fn call_method(&self, m: &Message, o: &ObjectPath<MethodSync>, i: &Tree<MethodSync>) -> MethodResult { self.0(m, o, i) }
+
+ fn box_method<H>(h: H) -> Self
+ where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static {
+ MethodSync(Box::new(h))
+ }
+}
+
+impl<'a> MethodType for MethodFnMut<'a> {
+ fn call_method(&self, m: &Message, o: &ObjectPath<MethodFnMut<'a>>, i: &Tree<MethodFnMut<'a>>) -> MethodResult {
+ let mut z = self.0.borrow_mut();
+ (&mut *z)(m, o, i)
+ }
+
+ fn box_method<H>(h: H) -> Self
+ where H: Fn(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + Send + Sync + 'static {
+ MethodFnMut(Box::new(RefCell::new(h)))
+ }
+}
+
+#[derive(Debug)]
+/// A D-Bus Method.
+pub struct Method<M> {
+ cb: M,
+ name: Arc<Member<'static>>,
+ i_args: Vec<Argument>,
+ o_args: Vec<Argument>,
+ anns: Annotations,
+}
+
+impl<M> Method<M> {
+ /// 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
+ }
+
+ /// Add 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
+ }
+ /// Add an annotation that this entity is deprecated.
+ pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
+}
+
+impl<M: MethodType> Method<M> {
+ /// Call the Method.
+ pub fn call(&self, m: &Message, o: &ObjectPath<M>, i: &Tree<M>) -> MethodResult { self.cb.call_method(m, o, i) }
+
+ fn new(n: Member<'static>, cb: M) -> Self { Method { name: Arc::new(n), i_args: vec!(),
+ o_args: vec!(), anns: Annotations::new(), cb: cb } }
+}
+
+
+#[derive(Debug)]
+/// Represents a D-Bus interface.
+pub struct Interface<M> {
+ name: Arc<IfaceName<'static>>,
+ methods: ArcMap<Member<'static>, Method<M>>,
+ signals: ArcMap<Member<'static>, Signal>,
+ properties: ArcMap<String, Property<M>>,
+ anns: Annotations,
+}
+
+impl<M> Interface<M> {
+ /// Adds a method to the interface.
+ pub fn add_m(mut self, m: Method<M>) -> Self { self.methods.insert(m.name.clone(), Arc::new(m)); self }
+ /// Adds a signal to the interface.
+ pub fn add_s(mut self, s: Signal) -> Self { self.signals.insert(s.name.clone(), Arc::new(s)); self }
+ /// Adds a signal to the interface. Lets you keep another clone of the signal
+ /// (which you can use to emit the signal, once it belongs to an object path).
+ ///
+ /// Note: You are not allowed to add a signal to more than one interface.
+ pub fn add_s_arc(mut self, s: Arc<Signal>) -> Self { self.signals.insert(s.name.clone(), s); self }
+ /// Adds a signal to the interface. Returns a reference to the signal
+ /// (which you can use to emit the signal, once it belongs to an object path).
+ pub fn add_s_ref(&mut self, s: Signal) -> Arc<Signal> {
+ let s = Arc::new(s);
+ self.signals.insert(s.name.clone(), s.clone());
+ s
+ }
+
+ /// Adds a property to the interface.
+ pub fn add_p(mut self, p: Property<M>) -> Self { self.properties.insert(p.name.clone(), Arc::new(p)); self }
+ /// Adds a property to the interface. Lets you keep another clone of the property
+ /// (which you can use to get and set the current value of the property).
+ ///
+ /// Note: You are not allowed to add a property to more than one interface. Later function calls might panic if you do so.
+ pub fn add_p_arc(mut self, p: Arc<Property<M>>) -> Self { self.properties.insert(p.name.clone(), p); self }
+ /// Adds a property to the interface. Returns a reference to the property
+ /// (which you can use to get and set the current value of the property).
+ pub fn add_p_ref(&mut self, p: Property<M>) -> Arc<Property<M>> {
+ let p = Arc::new(p);
+ self.properties.insert(p.name.clone(), p.clone());
+ p
+ }
+
+ /// Add an annotation to this Inteface.
+ 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") }
+
+ fn new(t: IfaceName<'static>) -> Interface<M> {
+ Interface { name: Arc::new(t), methods: BTreeMap::new(), signals: BTreeMap::new(),
+ properties: BTreeMap::new(), anns: Annotations::new()
+ }
+ }
+
+}
+
+#[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",
+ }
+ }
+}
+
+#[derive(Debug)]
+/// A D-Bus Property.
+pub struct Property<M> {
+ name: Arc<String>,
+ value: Mutex<MessageItem>,
+ emits: EmitsChangedSignal,
+ rw: Access,
+ set_cb: Option<M>,
+ owner: Mutex<Option<(Arc<Path<'static>>, Arc<IfaceName<'static>>)>>,
+ anns: Annotations,
+}
+
+impl<M: MethodType> Property<M> {
+ /// Gets the value of the Property.
+ pub fn get_value(&self) -> MessageItem {
+ self.value.lock().unwrap().clone()
+ }
+
+ /// Gets the signal (if any) associated with the Property.
+ pub fn get_signal(&self) -> Option<Message> {
+ self.owner.lock().unwrap().as_ref().map(|&(ref p, ref i)| {
+ Message::signal(&p, &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
+ .append(String::from(&***i))
+ })
+ }
+
+ /// Returns error if "emits" is "Const", and the property is in a
+ /// tree. Returns messages to be sent over a connection, this
+ /// could be the PropertiesChanged signal.
+ pub fn set_value(&self, m: MessageItem) -> Result<Vec<Message>,()> {
+ let ss = match self.emits {
+ EmitsChangedSignal::False => None,
+ EmitsChangedSignal::Const => if self.get_signal().is_some() { return Err(()) } else { None },
+ EmitsChangedSignal::True => self.get_signal().map(|s|
+ s.append2(arg::Dict::new(vec!((&**self.name, arg::Variant(m.clone())))), arg::Array::<&str, _>::new(vec!()))
+ ),
+ EmitsChangedSignal::Invalidates => self.get_signal().map(|s| {
+ s.append2(arg::Dict::<&str, arg::Variant<MessageItem>, _>::new(vec!()), arg::Array::new(vec!(&**self.name)))
+ }),
+ };
+ *self.value.lock().unwrap() = m;
+ Ok(ss.map(|s| vec!(s)).unwrap_or(vec!()))
+ }
+
+ /// Builder method that allows setting the Property's signal
+ /// behavior when changed.
+ pub fn emits_changed(mut self, e: EmitsChangedSignal) -> Self {
+ self.emits = e;
+ assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const);
+ self
+ }
+
+ /// Builder method that allows setting the Property as readable,
+ /// writable, or both.
+ pub fn access(mut self, e: Access) -> Self {
+ self.rw = e;
+ assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const);
+ self
+ }
+
+ /// Helper method to check accessibility before getting a value.
+ pub fn remote_get(&self, _: &Message) -> Result<MessageItem, MethodErr> {
+ // TODO: We should be able to call a user-defined callback here instead...
+ if self.rw == Access::Write { return Err(MethodErr::failed(&format!("Property {} is write only", &self.name))) }
+ Ok(self.get_value())
+ }
+
+ /// Helper method to verify and extract a MessageItem from a Set message
+ pub fn verify_remote_set(&self, m: &Message) -> Result<MessageItem, MethodErr> {
+ let items = m.get_items();
+ let s: &MessageItem = try!(items.get(2).ok_or_else(|| MethodErr::no_arg())
+ .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
+
+ if self.rw == Access::Read { Err(MethodErr::ro_property(&self.name)) }
+ else if s.type_sig() != self.value.lock().unwrap().type_sig() {
+ Err(MethodErr::failed(&format!("Property {} cannot change type to {}", &self.name, s.type_sig())))
+ }
+ else { Ok(s.clone()) }
+ }
+
+ fn remote_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> Result<Vec<Message>, MethodErr> {
+ if let Some(ref cb) = self.set_cb {
+ cb.call_method(m, o, t)
+ }
+ else {
+ let s = try!(self.verify_remote_set(m));
+ self.set_value(s).map_err(|_| MethodErr::ro_property(&self.name))
+ }
+ }
+
+ /// Add an annotation to this Property.
+ 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") }
+
+ fn new(s: String, i: MessageItem) -> Property<M> {
+ Property { name: Arc::new(s), emits: EmitsChangedSignal::True, rw: Access::Read,
+ value: Mutex::new(i), owner: Mutex::new(None), anns: Annotations::new(), set_cb: None }
+ }
+}
+
+impl Property<MethodSync> {
+ /// Sets a callback to be called when a "Set" call is coming in from the remote side.
+ /// Might change to something more ergonomic.
+ /// For multi-thread use.
+ pub fn on_set<H>(mut self, m: H) -> Self
+ where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static {
+ self.set_cb = Some(MethodSync::box_method(m));
+ self
+ }
+}
+
+impl<'a> Property<MethodFn<'a>> {
+ /// Sets a callback to be called when a "Set" call is coming in from the remote side.
+ /// Might change to something more ergonomic.
+ /// For single-thread use.
+ pub fn on_set<H: 'a>(mut self, m: H) -> Self
+ where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult {
+ self.set_cb = Some(MethodFn(Box::new(m)));
+ self
+ }
+}
+
+impl<'a> Property<MethodFnMut<'a>> {
+ /// Sets a callback to be called when a "Set" call is coming in from the remote side.
+ /// Might change to something more ergonomic.
+ /// For single-thread use.
+ pub fn on_set<H: 'a>(mut self, m: H) -> Self
+ where H: FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult {
+ self.set_cb = Some(MethodFnMut(Box::new(RefCell::new(m))));
+ self
+ }
+}
+
+
+#[derive(Debug)]
+/// A D-Bus Signal.
+pub struct Signal {
+ name: Arc<Member<'static>>,
+ arguments: Vec<Argument>,
+ owner: Mutex<Option<(Arc<Path<'static>>, Arc<IfaceName<'static>>)>>,
+ anns: Annotations,
+}
+
+impl Signal {
+ /// Returns a message which emits the signal when sent.
+ /// Panics if the signal is not inserted in an object path.
+ pub fn emit(&self, items: &[MessageItem]) -> Message {
+ let mut m = {
+ let lock = self.owner.lock().unwrap();
+ let &(ref p, ref i) = lock.as_ref().unwrap();
+ Message::signal(p, i, &self.name)
+ };
+ m.append_items(items);
+ m
+ }
+
+ /// Returns a message which emits the signal when sent.
+ /// Panics if the signal is not inserted in an object path.
+ ///
+ /// Same as "emit" but does not take a "MessageItem" argument.
+ pub fn msg(&self) -> Message { self.emit(&[]) }
+
+ /// 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 "rguments to the Signel.
+ 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") }
+}
+
+fn introspect_map<T, I: fmt::Display, C: Fn(&T) -> (String, String)>
+ (h: &ArcMap<I, T>, name: &str, indent: &str, func: C) -> String {
+
+ h.iter().fold("".into(), |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!("/") }
+ )
+ })
+}
+
+#[derive(Debug)]
+/// A D-Bus Object Path.
+pub struct ObjectPath<M> {
+ name: Arc<Path<'static>>,
+ ifaces: ArcMap<IfaceName<'static>, Interface<M>>,
+}
+
+impl<M: MethodType> ObjectPath<M> {
+ fn new(p: Path<'static>) -> ObjectPath<M> {
+ ObjectPath { name: Arc::new(p), ifaces: BTreeMap::new() }
+ }
+
+ fn get_iface<'a>(&'a self, i: Option<&'a CStr>) -> Result<&Arc<Interface<M>>, MethodErr> {
+ let iface_name = try!(i.ok_or_else(|| MethodErr::invalid_arg(&0)));
+ 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_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> MethodResult {
+ let (iname, p) = m.get2();
+ let iface = try!(self.get_iface(iname));
+ let prop_name: &str = try!(p.ok_or_else(|| MethodErr::invalid_arg(&1)));
+ let prop: &Property<M> = try!(iface.properties.get(&String::from(prop_name))
+ .ok_or_else(|| MethodErr::no_property(&prop_name)));
+ let mut r = try!(prop.remote_set(m, o, t));
+ r.push(m.method_return());
+ Ok(r)
+ }
+
+ fn prop_get(&self, m: &Message) -> MethodResult {
+ let (iname, p) = m.get2();
+ let iface = try!(self.get_iface(iname));
+ let prop_name: &str = try!(p.ok_or_else(|| MethodErr::invalid_arg(&1)));
+ let prop: &Property<M> = try!(iface.properties.get(&String::from(prop_name))
+ .ok_or_else(|| MethodErr::no_property(&prop_name)));
+ let r = try!(prop.remote_get(m));
+ Ok(vec!(m.method_return().append1(arg::Variant(r))))
+ }
+
+ fn prop_get_all(&self, m: &Message) -> MethodResult {
+ let iface = try!(self.get_iface(m.get1()));
+ let mut q = vec!();
+ for v in iface.properties.values() {
+ q.push((&**v.name, arg::Variant(try!(v.remote_get(m)))));
+ }
+ Ok(vec!(m.method_return().append1(arg::Dict::new(q))))
+ }
+
+ fn add_property_handler(&mut self) {
+ let ifname = IfaceName::from("org.freedesktop.DBus.Properties");
+ if self.ifaces.contains_key(&ifname) { return };
+ let f: Factory<M> = Factory(PhantomData);
+
+ let i = Interface::<M>::new(ifname)
+ .add_m(f.method_sync("Get", |m,o,_| o.prop_get(m) )
+ .inarg::<&str,_>("interface_name")
+ .inarg::<&str,_>("property_name")
+ .outarg::<arg::Variant<()>,_>("value"))
+ .add_m(f.method_sync("GetAll", |m,o,_| o.prop_get_all(m))
+ .inarg::<&str,_>("interface_name")
+ .outarg::<arg::Dict<&str, arg::Variant<()>, ()>,_>("props"))
+ .add_m(f.method_sync("Set", |m,o,t| o.prop_set(m, o, t))
+ .inarg::<&str,_>("interface_name")
+ .inarg::<&str,_>("property_name")
+ .inarg::<arg::Variant<()>,_>("value"));
+ self.ifaces.insert(i.name.clone(), Arc::new(i));
+ }
+
+ /// Add an Interface to this Object Path.
+ pub fn add(mut self, p: Interface<M>) -> Self {
+ use std::mem;
+ for s in p.signals.values() {
+ let n = Some((self.name.clone(), p.name.clone()));
+ let o = mem::replace(&mut *s.owner.lock().unwrap(), n);
+ assert!(o.is_none(), "Signal {} already added to object path", s.name);
+ };
+ for s in p.properties.values() {
+ let n = Some((self.name.clone(), p.name.clone()));
+ let o = mem::replace(&mut *s.owner.lock().unwrap(), n);
+ assert!(o.is_none(), "Property {} already added to object path", s.name);
+ };
+ if !p.properties.is_empty() { self.add_property_handler(); }
+ self.ifaces.insert(p.name.clone(), Arc::new(p));
+ self
+ }
+
+ /// Adds introspection support for this object path.
+ pub fn introspectable(self) -> Self {
+ let ifname: IfaceName = "org.freedesktop.DBus.Introspectable".into();
+ if self.ifaces.contains_key(&ifname) { return self };
+ let f: Factory<M> = Factory(PhantomData);
+ self.add(Interface::<M>::new(ifname)
+ .add_m(f.method_sync("Introspect",
+ |m,o,t| Ok(vec!(m.method_return().append(o.introspect(t)))))
+ .out_arg(("xml_data", "s"))))
+ }
+
+ fn handle(&self, m: &Message, t: &Tree<M>) -> MethodResult {
+ let i = try!(m.interface().and_then(|i| self.ifaces.get(&i)).ok_or(
+ ("org.freedesktop.DBus.Error.UnknownInterface", "Unknown interface")));
+ let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or(
+ ("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")));
+ me.call(m, &self, t)
+ }
+
+ fn introspect(&self, tree: &Tree<M>) -> String {
+ let ifacestr = introspect_map(&self.ifaces, "interface", " ", |iv|
+ (format!(""), format!("{}{}{}{}",
+ introspect_map(&iv.methods, "method", " ", |m| (format!(""), format!("{}{}{}",
+ Argument::introspect_all(&m.i_args, " ", " direction=\"in\""),
+ Argument::introspect_all(&m.o_args, " ", " direction=\"out\""),
+ m.anns.introspect(" ")
+ ))),
+ introspect_map(&iv.properties, "property", " ", |p| (
+ format!(" type=\"{}\" access=\"{}\"", p.get_value().type_sig(), p.rw.introspect()),
+ p.anns.introspect(" ")
+ )),
+ introspect_map(&iv.signals, "signal", " ", |s| (format!(""), format!("{}{}",
+ Argument::introspect_all(&s.arguments, " ", ""),
+ s.anns.introspect(" ")
+ ))),
+ iv.anns.introspect(" ")
+ ))
+ );
+ 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_managed_objects(&self, t: &Tree<M>) -> MessageItem {
+ let mut paths = t.children(&self, false);
+ paths.push(&self);
+ MessageItem::Array(
+ paths.iter().map(|p| ((&*p.name).clone().into(), MessageItem::Array(
+ p.ifaces.values().map(|i| ((&**i.name).into(), MessageItem::Array(
+ i.properties.values().map(|pp| ((&**pp.name).into(), Box::new(pp.get_value()
+ ).into()).into()).collect(), "{sv}".into()
+ )).into()).collect(), "{sa{sv}}".into()
+ )).into()).collect(), "{oa{sa{sv}}}".into()
+ )
+ }
+
+ /// 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(self) -> Self {
+ let ifname: IfaceName = "org.freedesktop.DBus.ObjectManager".into();
+ if self.ifaces.contains_key(&ifname) { return self };
+ let f: Factory<M> = Factory(PhantomData);
+ self.add(Interface::<M>::new(ifname)
+ .add_m(f.method_sync("GetManagedObjects",
+ |m,o,t| Ok(vec!(m.method_return().append(o.get_managed_objects(t)))))
+ .out_arg("a{oa{sa{sv}}}")))
+ }
+}
+
+/// 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: 'a> {
+ iter: I,
+ conn: &'a Connection,
+ tree: &'a Tree<M>,
+}
+
+impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType> Iterator for TreeServer<'a, I, M> {
+ 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;
+ }
+ }
+}
+
+/// A collection of object paths.
+#[derive(Debug)]
+pub struct Tree<M> {
+ paths: ArcMap<Path<'static>, ObjectPath<M>>
+}
+
+impl<M: MethodType> Tree<M> {
+
+ fn children(&self, o: &ObjectPath<M>, direct_only: bool) -> Vec<&ObjectPath<M>> {
+ 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()
+ }
+
+ /// Add an Object Path to this Tree.
+ ///
+ /// Note: This does not unregister 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(mut self, p: ObjectPath<M>) -> Self {
+ self.paths.insert(p.name.clone(), Arc::new(p));
+ self
+ }
+
+ /// Adds an ObjectPath to this Tree. Returns a reference to the ObjectPath.
+ /// The note for add() also applies here.
+ pub fn add_o_ref(&mut self, p: ObjectPath<M>) -> Arc<ObjectPath<M>> {
+ let name = p.name.clone();
+ let o = Arc::new(p);
+ self.paths.insert(name, o.clone());
+ o
+ }
+
+ /// 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>>> {
+ // 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(())
+ }
+
+ /// Handles a message. Will return None in case the object path was not
+ /// found, 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!(m.error(&e.0, &CString::new(e.1).unwrap()))))) }
+ }
+
+ /// 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> {
+ TreeServer { iter: i, tree: &self, conn: c }
+ }
+}
+
+/// The factory is used to create object paths, interfaces, methods etc.
+///
+/// There are three factories:
+///
+/// **Fn** - all methods are `Fn()`.
+///
+/// **FnMut** - 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.
+///
+/// **Sync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods
+/// can be called from different threads in parallel.
+#[derive(Debug, Copy, Clone)]
+pub struct Factory<M>(PhantomData<M>);
+
+impl<'a> Factory<MethodFn<'a>> {
+
+ /// Creates a new factory for single-thread use.
+ pub fn new_fn() -> Self { Factory(PhantomData) }
+
+ /// Creates a new method for single-thread use.
+ pub fn method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFn<'b>>
+ where H: Fn(&Message, &ObjectPath<MethodFn<'b>>, &Tree<MethodFn<'b>>) -> MethodResult, T: Into<Member<'static>> {
+ Method::new(t.into(), MethodFn(Box::new(handler)))
+ }
+
+ /// Creates a new property for single-thread use.
+ pub fn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFn<'b>> {
+ Property::new(t.into(), i.into())
+ }
+
+ /// Creates a new interface for single-thread use.
+ pub fn interface<'b, T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodFn<'b>> { Interface::new(t.into()) }
+
+ /// Creates a new tree for single-thread use.
+ pub fn tree<'b>(&self) -> Tree<MethodFn<'b>> { Tree { paths: BTreeMap::new() }}
+
+ /// Creates a new object path for single-thread use.
+ pub fn object_path<'b, T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodFn<'b>> { ObjectPath::new(t.into()) }
+}
+
+impl<'a> Factory<MethodFnMut<'a>> {
+
+ /// Creates a new factory for single-thread + mutable fns use.
+ pub fn new_fnmut() -> Self { Factory(PhantomData) }
+
+ /// Creates a new method for single-thread use.
+ /// This method can mutate its environment, so it will panic in case
+ /// it is called recursively.
+ pub fn method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFnMut<'b>>
+ where H: FnMut(&Message, &ObjectPath<MethodFnMut<'b>>, &Tree<MethodFnMut<'b>>) -> MethodResult, T: Into<Member<'static>> {
+ Method::new(t.into(), MethodFnMut(Box::new(RefCell::new(handler))))
+ }
+
+ /// Creates a new mutable property for single-thread use.
+ pub fn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFnMut<'b>> {
+ Property::new(t.into(), i.into())
+ }
+
+ /// Creates a new mutable interface for single-thread use.
+ pub fn interface<'b, T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodFnMut<'b>> { Interface::new(t.into()) }
+
+ /// Creates a new mutable tree for single-thread use.
+ pub fn tree<'b>(&self) -> Tree<MethodFnMut<'b>> { Tree { paths: BTreeMap::new() }}
+
+ /// Creates a new mutable object path for single-thread use.
+ pub fn object_path<'b, T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodFnMut<'b>> { ObjectPath::new(t.into()) }
+}
+
+impl Factory<MethodSync> {
+
+ /// Creates a new factory for multi-thread use.
+ /// Trees created will be able to Send and Sync, i e,
+ /// it can handle several messages in parallel.
+ pub fn new_sync() -> Self { Factory(PhantomData) }
+
+ /// Creates a new method for multi-thread use.
+ /// This puts bounds on the callback to enable it to be called from several threads
+ /// in parallel.
+ pub fn method<H, T>(&self, t: T, handler: H) -> Method<MethodSync>
+ where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
+ Method::new(t.into(), MethodSync(Box::new(handler)))
+ }
+
+ /// Creates a new property for multi-threaded use.
+ pub fn property<T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodSync> {
+ Property::new(t.into(), i.into())
+ }
+
+ /// Creates a new interface for multi-threaded use.
+ pub fn interface<T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodSync> { Interface::new(t.into()) }
+
+ /// Creates a new tree for multi-threaded use.
+ pub fn tree(&self) -> Tree<MethodSync> { Tree { paths: BTreeMap::new() }}
+
+ /// Creates a new object path for multi-threaded use.
+ pub fn object_path<T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodSync> { ObjectPath::new(t.into()) }
+}
+
+impl<M> Factory<M> {
+ /// Create a Signal.
+ pub fn signal<T: Into<Member<'static>>>(&self, t: T) -> Signal {
+ Signal { name: Arc::new(t.into()), arguments: vec!(), owner: Mutex::new(None), anns: Annotations::new() }
+ }
+}
+
+impl<M: MethodType> Factory<M> {
+ /// Creates a new method with bounds enough to be used in all trees.
+ pub fn method_sync<H, T>(&self, t: T, handler: H) -> Method<M>
+ where H: Fn(&Message, &ObjectPath<M>, &Tree<M>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
+ Method::new(t.into(), M::box_method(handler))
+ }
+}
+
+#[test]
+fn factory_test() {
+ let f = Factory::new_fn();
+ f.interface("com.example.hello").deprecated();
+ let b = 5i32;
+ f.method("GetSomething", |m,_,_| Ok(vec!({ let mut z = m.method_return(); z.append_items(&[b.into()]); z})));
+ let t = f.tree().add(f.object_path("/funghi").add(f.interface("a.b.c").deprecated()));
+ let t = t.add(f.object_path("/ab")).add(f.object_path("/a")).add(f.object_path("/a/b/c")).add(f.object_path("/a/b"));
+ assert_eq!(t.children(t.paths.get(&Path::from("/a")).unwrap(), true).len(), 1);
+}
+
+#[test]
+fn test_sync_prop() {
+ let f = Factory::new_sync();
+ let mut i = f.interface("com.example.echo");
+ let p = i.add_p_ref(f.property("EchoCount", 7i32));
+ let tree1 = Arc::new(f.tree().add(f.object_path("/echo").introspectable().add(i)));
+ let tree2 = tree1.clone();
+ println!("{:#?}", tree2);
+ ::std::thread::spawn(move || {
+ let r = p.set_value(9i32.into()).unwrap();
+ let signal = r.get(0).unwrap();
+ assert_eq!(signal.msg_type(), MessageType::Signal);
+ let mut msg = Message::new_method_call("com.example.echoserver", "/echo", "com.example", "dummy").unwrap();
+ super::message::message_set_serial(&mut msg, 3);
+ tree2.handle(&msg);
+ });
+
+ let mut msg = Message::new_method_call("com.example.echoserver", "/echo", "org.freedesktop.DBus.Properties", "Get").unwrap()
+ .append("com.example.echo").append("EchoCount");
+ super::message::message_set_serial(&mut msg, 4);
+ let r = tree1.handle(&msg).unwrap();
+ let r1 = r.get(0).unwrap();
+ println!("{:?}", r1.get_items());
+ let vv: super::arg::Variant<i32> = r1.get1().unwrap();
+ assert!(vv.0 == 7 || vv.0 == 9);
+}
+
+/* This test case no longer works, for unknown reason, see
+ https://github.com/diwic/dbus-rs/issues/27
+
+#[test]
+fn prop_lifetime_simple() {
+ let count;
+ let f = Factory::new_fnmut();
+ count = Arc::new(f.property("changes", 0i32));
+ let mut i = f.interface("com.example.dbus.rs").add_p_arc(count.clone());
+
+ let _setme = i.add_p_ref(f.property("setme", 0u8).access(Access::ReadWrite).on_set(|_,_,_| {
+ let v: i32 = count.get_value().inner().unwrap();
+ count.set_value((v + 1).into()).unwrap();
+ Ok(vec!())
+ }));
+}
+*/
+
+#[test]
+fn prop_server() {
+ let setme: Arc<RefCell<Option<Arc<Property<_>>>>>; // Yikes!
+ setme = Arc::new(RefCell::new(None));
+ let f = Factory::new_fnmut();
+ let mut i = f.interface("com.example.dbus.rs");
+ let count = i.add_p_ref(f.property("changes", 0i32));
+ let count2 = count.clone();
+ let setme2 = setme.clone();
+ let setme3 = Arc::new(f.property("setme", 0u8).access(Access::ReadWrite).on_set(move |m,_,_| {
+ let ss2 = setme2.borrow();
+ let ss = ss2.as_ref().unwrap();
+ let s = try!(ss.verify_remote_set(m));
+ let r = try!(ss.set_value(s).map_err(|_| MethodErr::ro_property(&ss.name)));
+ let v: i32 = count2.get_value().inner().unwrap();
+ count2.set_value((v + 1).into()).unwrap();
+ Ok(r)
+ }));
+ *setme.borrow_mut() = Some(setme3.clone());
+ let i = i.add_p_arc(setme3);
+
+ let tree = f.tree().add(f.object_path("/example").add(i));
+
+ let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Get").unwrap()
+ .append("com.example.dbus.rs").append("changes");
+ super::message::message_set_serial(&mut msg, 10);
+ let r = tree.handle(&msg).unwrap();
+ let r1 = r.get(0).unwrap();
+ let ii = r1.get_items();
+ let vv: &MessageItem = ii.get(0).unwrap().inner().unwrap();
+ let v: i32 = vv.inner().unwrap();
+ assert_eq!(v, 0);
+
+ // Read-only
+ let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append("com.example.dbus.rs").append("changes").append(5i32);
+ super::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()
+ .append("com.example.dbus.rs").append("setme").append(8i32);
+ super::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()
+ .append("com.example.dbus.rs").append("setme").append(Box::new(9u8.into()));
+ super::message::message_set_serial(&mut msg, 30);
+ let mut r = tree.handle(&msg).unwrap();
+
+ println!("{:?}", r[0].as_result());
+
+ let c: i32 = count.get_value().inner().unwrap();
+ assert_eq!(c, 1);
+
+}
+
+
+#[test]
+fn test_introspection() {
+ let f = Factory::new_sync();
+ 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("EchoCount", 7i32))
+ .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);
+}
+
diff --git a/third_party/rust/dbus/src/objpath.rs b/third_party/rust/dbus/src/objpath.rs
new file mode 100644
index 0000000000..86d2c3f01a
--- /dev/null
+++ b/third_party/rust/dbus/src/objpath.rs
@@ -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());
+
+}
+
diff --git a/third_party/rust/dbus/src/prop.rs b/third_party/rust/dbus/src/prop.rs
new file mode 100644
index 0000000000..8c52872e1d
--- /dev/null
+++ b/third_party/rust/dbus/src/prop.rs
@@ -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); }
+ };
+}
+
diff --git a/third_party/rust/dbus/src/signalargs.rs b/third_party/rust/dbus/src/signalargs.rs
new file mode 100644
index 0000000000..6eb92950cb
--- /dev/null
+++ b/third_party/rust/dbus/src/signalargs.rs
@@ -0,0 +1,107 @@
+use arg;
+use {Message, MessageType, BusName, Path, Interface, Member, MatchRule};
+
+/// 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 match rule matching this signal.
+ ///
+ /// If sender and/or path is None, matches all senders and/or paths.
+ fn match_rule<'a>(sender: Option<&'a BusName>, path: Option<&'a Path>) -> MatchRule<'a> {
+ let mut m: MatchRule = Default::default();
+ m.sender = sender.map(|x| x.clone());
+ m.path = path.map(|x| x.clone());
+ m.msg_type = Some(MessageType::Signal);
+ m.interface = Some(Self::INTERFACE.into());
+ m.member = Some(Self::NAME.into());
+ m
+ }
+
+
+ /// 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 {
+ Self::match_rule(sender, path).match_str()
+ }
+}
+
+#[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;
+ }
+ }
+}
diff --git a/third_party/rust/dbus/src/stdintf.rs b/third_party/rust/dbus/src/stdintf.rs
new file mode 100644
index 0000000000..7a35c7fc8e
--- /dev/null
+++ b/third_party/rust/dbus/src/stdintf.rs
@@ -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)
+ }
+}
+
+
+}
diff --git a/third_party/rust/dbus/src/strings.rs b/third_party/rust/dbus/src/strings.rs
new file mode 100644
index 0000000000..8bd077d08e
--- /dev/null
+++ b/third_party/rust/dbus/src/strings.rs
@@ -0,0 +1,216 @@
+// 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()))
+ }
+
+ /// Converts this struct to a CString.
+ pub fn into_cstring(self) -> CString { 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() } }
+
+impl<'m> From<$t<'m>> for CString { fn from(s: $t<'m>) -> CString { s.0.into_owned() } }
+
+
+/// #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)");
+}
diff --git a/third_party/rust/dbus/src/tree/factory.rs b/third_party/rust/dbus/src/tree/factory.rs
new file mode 100644
index 0000000000..2157fc4110
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/factory.rs
@@ -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);
+}
diff --git a/third_party/rust/dbus/src/tree/leaves.rs b/third_party/rust/dbus/src/tree/leaves.rs
new file mode 100644
index 0000000000..3d358f7e0c
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/leaves.rs
@@ -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);
+}
diff --git a/third_party/rust/dbus/src/tree/methodtype.rs b/third_party/rust/dbus/src/tree/methodtype.rs
new file mode 100644
index 0000000000..38b0669d77
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/methodtype.rs
@@ -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 }
+ }
+}
diff --git a/third_party/rust/dbus/src/tree/mod.rs b/third_party/rust/dbus/src/tree/mod.rs
new file mode 100644
index 0000000000..00257235fb
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/mod.rs
@@ -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;
diff --git a/third_party/rust/dbus/src/tree/objectpath.rs b/third_party/rust/dbus/src/tree/objectpath.rs
new file mode 100644
index 0000000000..cc2fb0ba05
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/objectpath.rs
@@ -0,0 +1,553 @@
+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>>,
+ default_iface: Option<IfaceName<'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 iname = m.interface().or_else(|| { self.default_iface.clone() });
+ let i = try!(iname.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
+ }
+
+ /// Builder function that sets what interface should be dispatched on an incoming
+ /// method call without interface.
+ pub fn default_interface(mut self, i: IfaceName<'static>) -> Self {
+ self.default_iface = Some(i);
+ 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, default_iface: None }
+}
+
+
+/// 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_set_default_interface() {
+ let iface_name: IfaceName<'_> = "com.example.echo".into();
+ let f = super::Factory::new_fn::<()>();
+ let t = f.object_path("/echo", ()).default_interface(iface_name.clone());
+ assert_eq!(t.default_iface, Some(iface_name));
+}
+
+
+#[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);
+}
+
diff --git a/third_party/rust/dbus/src/tree/utils.rs b/third_party/rust/dbus/src/tree/utils.rs
new file mode 100644
index 0000000000..5b1418908b
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/utils.rs
@@ -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;
+}
+
diff --git a/third_party/rust/dbus/src/watch.rs b/third_party/rust/dbus/src/watch.rs
new file mode 100644
index 0000000000..e1959f1085
--- /dev/null
+++ b/third_party/rust/dbus/src/watch.rs
@@ -0,0 +1,255 @@
+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 },
+ }
+ }
+/*
+ pub (crate) unsafe fn from_raw(watch: *mut ffi::DBusWatch) -> Self {
+ let mut w = Watch { fd: ffi::dbus_watch_get_unix_fd(watch), read: false, write: false};
+ let enabled = ffi::dbus_watch_get_enabled(watch) != 0;
+ if enabled {
+ let flags = ffi::dbus_watch_get_flags(watch);
+ w.read = (flags & WatchEvent::Readable as c_uint) != 0;
+ w.write = (flags & WatchEvent::Writable as c_uint) != 0;
+ }
+ w
+ }
+*/
+}
+
+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::nfds_t, 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!() };
+ }
+ }
+ }
+}