summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus/src/crossroads/crossroads.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/dbus/src/crossroads/crossroads.rs')
-rw-r--r--third_party/rust/dbus/src/crossroads/crossroads.rs245
1 files changed, 245 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);
+ }
+}