summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus/src/crossroads
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/src/crossroads
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/src/crossroads')
-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
5 files changed, 671 insertions, 0 deletions
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!())
+}
+
+