1use std::cmp::Ordering as COrdering;
2use std::collections::hash_map::Iter;
3use std::collections::HashMap;
4use std::fmt::Write;
5use std::fmt::{Debug, Formatter};
6use std::mem::MaybeUninit;
7use std::sync::atomic::{AtomicU8, Ordering};
8use std::sync::Arc;
9
10use std::path::Path;
11
12use super::rustbus_core;
13use super::MsgQueue;
14use rustbus_core::message_builder::{MarshalledMessage, MessageType};
15use rustbus_core::path::ObjectPath;
16
17static mut MAP_TUPLE: (AtomicU8, MaybeUninit<HashMap<String, CallHierarchy>>) =
18 (AtomicU8::new(0), MaybeUninit::uninit());
19
20unsafe fn init_empty_map(flag: u8) -> &'static HashMap<String, CallHierarchy> {
21 if flag == 0
22 && MAP_TUPLE
23 .0
24 .compare_exchange(0, 1, Ordering::AcqRel, Ordering::Relaxed)
25 .is_ok()
26 {
27 MAP_TUPLE.1 = MaybeUninit::new(HashMap::new());
28 MAP_TUPLE.0.store(2, Ordering::Release);
29 return &*MAP_TUPLE.1.as_ptr();
30 }
31 while MAP_TUPLE.0.load(Ordering::Acquire) != 2 {
32 std::hint::spin_loop();
33 }
34 &*MAP_TUPLE.1.as_ptr()
35}
36fn get_empty_map() -> &'static HashMap<String, CallHierarchy> {
37 unsafe {
38 let flag = MAP_TUPLE.0.load(Ordering::Acquire);
39 if flag == 2 {
40 return &*MAP_TUPLE.1.as_ptr();
41 }
42 init_empty_map(flag)
43 }
44}
45
46enum CallHandler {
47 Queue(MsgQueue),
48 Exact(MsgQueue),
49 Intro,
50 Nothing,
51 Drop,
52}
53impl Debug for CallHandler {
54 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55 match self {
56 CallHandler::Exact(_) => write!(f, "CallHandler::Exact"),
57 CallHandler::Queue(_) => write!(f, "CallHandler::Queue"),
58 CallHandler::Nothing => write!(f, "CallHandler::Nothing"),
59 CallHandler::Drop => write!(f, "CallHandler::Drop"),
60 CallHandler::Intro => write!(f, "CallHandler::Intro"),
61 }
62 }
63}
64impl CallHandler {
65 fn is_nothing(&self) -> bool {
66 matches!(self, CallHandler::Nothing)
67 }
68 fn get_queue(&self) -> Option<&MsgQueue> {
69 match self {
70 CallHandler::Queue(q) | CallHandler::Exact(q) => Some(q),
71 _ => None,
72 }
73 }
74}
75impl From<CallAction> for CallHandler {
76 fn from(action: CallAction) -> Self {
77 match action {
78 CallAction::Queue => CallHandler::Queue(MsgQueue::new()),
79 CallAction::Exact => CallHandler::Exact(MsgQueue::new()),
80 CallAction::Drop => CallHandler::Drop,
81 CallAction::Nothing => CallHandler::Nothing,
82 CallAction::Intro => CallHandler::Intro,
83 }
84 }
85}
86#[derive(Debug)]
87pub(crate) struct CallHierarchy {
88 children: HashMap<String, CallHierarchy>,
89 handler: CallHandler,
90}
91enum Status<'a> {
92 Queue(&'a MsgQueue),
93 Intro(Iter<'a, String, CallHierarchy>),
94 Dropped,
95 Unhandled(Iter<'a, String, CallHierarchy>),
96}
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum CallAction {
102 Drop,
104 Queue,
106 Exact,
108 Intro,
111 Nothing,
115}
116impl From<&CallHandler> for CallAction {
117 fn from(handler: &CallHandler) -> Self {
118 match handler {
119 CallHandler::Exact(_) => CallAction::Exact,
120 CallHandler::Queue(_) => CallAction::Queue,
121 CallHandler::Drop => CallAction::Drop,
122 CallHandler::Nothing => CallAction::Nothing,
123 CallHandler::Intro => CallAction::Intro,
124 }
125 }
126}
127impl CallHierarchy {
128 pub fn new() -> Self {
129 CallHierarchy {
130 handler: CallHandler::Drop,
131 children: HashMap::new(),
132 }
133 }
134 pub fn send(&self, msg: MarshalledMessage) -> Result<(), MarshalledMessage> {
135 let path = ObjectPath::from_str(msg.dynheader.object.as_ref().unwrap()).unwrap();
136 let tar_comps = path.components();
137 match self.send_inner(tar_comps) {
138 Status::Queue(queue) => {
139 queue.send(msg);
140 Ok(())
141 }
142 Status::Intro(keys) => Err(make_intro_msg(msg, keys)),
143 Status::Unhandled(_) | Status::Dropped => Err(make_object_not_found(msg)),
144 }
145 }
146 fn send_inner<'a>(&self, mut tar_comps: impl Iterator<Item = &'a str>) -> Status {
147 match tar_comps.next() {
148 Some(child) => match self.children.get(child) {
149 Some(child) => match child.send_inner(tar_comps) {
150 Status::Unhandled(keys) => match &self.handler {
151 CallHandler::Nothing => Status::Unhandled(keys),
152 CallHandler::Queue(q) => Status::Queue(q),
153 CallHandler::Intro => Status::Intro(keys),
154 CallHandler::Exact(_) | CallHandler::Drop => Status::Dropped,
155 },
156 handled => handled,
157 },
158 None => match &self.handler {
159 CallHandler::Queue(q) => Status::Queue(q),
160 CallHandler::Nothing => Status::Unhandled(get_empty_map().iter()),
161 CallHandler::Intro | CallHandler::Exact(_) | CallHandler::Drop => {
162 Status::Dropped
163 }
164 },
165 },
166 None => match &self.handler {
167 CallHandler::Queue(q) | CallHandler::Exact(q) => Status::Queue(q),
168 CallHandler::Nothing => Status::Unhandled(self.children.iter()),
169 CallHandler::Drop => Status::Dropped,
170 CallHandler::Intro => Status::Intro(self.children.iter()),
171 },
172 }
173 }
174 fn insert_inner<'a>(
175 &mut self,
176 mut tar_comps: impl Iterator<Item = &'a str>,
177 action: CallAction,
178 ) -> bool {
179 match tar_comps.next() {
180 Some(child) => match self.children.get_mut(child) {
181 Some(entry) => {
182 if entry.insert_inner(tar_comps, action) {
183 true
184 } else {
185 self.children.remove(child);
186 !(self.children.is_empty() && self.handler.is_nothing())
187 }
188 }
189 None => {
190 let mut hierarchy = CallHierarchy::new();
191 hierarchy.handler = CallHandler::Nothing;
192 if hierarchy.insert_inner(tar_comps, action) {
193 self.children.insert(child.to_string(), hierarchy);
194 true
196 } else {
197 !matches!(self.handler, CallHandler::Nothing)
198 }
199 }
200 },
201 None => {
202 self.handler = action.into();
203 if self.handler.is_nothing() {
205 !self.children.is_empty()
206 } else {
207 true
208 }
209 }
210 }
211 }
212 pub fn insert_path(&mut self, path: &ObjectPath, handler: CallAction) {
213 let tar_comps = path.components();
214 self.insert_inner(tar_comps, handler);
215 }
216 fn find_inner<'a>(&self, mut tar_comps: impl Iterator<Item = &'a str>) -> Option<&CallHandler> {
217 match tar_comps.next() {
218 Some(child) => self.children.get(child)?.find_inner(tar_comps),
219 None => Some(&self.handler),
220 }
221 }
222 fn find_handler(&self, path: &ObjectPath) -> Option<&CallHandler> {
223 let tar_comps = path.components();
224 self.find_inner(tar_comps)
225 }
226 pub fn get_queue(&self, path: &ObjectPath) -> Option<&MsgQueue> {
227 let handler = self.find_handler(path)?;
228 handler.get_queue()
229 }
230 pub fn get_action(&self, path: &ObjectPath) -> Option<CallAction> {
231 let handler = self.find_handler(path)?;
232 Some(handler.into())
233 }
234 fn is_match_inner<'a>(
235 &self,
236 mut org_comps: impl Iterator<Item = &'a str>,
237 mut msg_comps: impl Iterator<Item = &'a str>,
238 ) -> bool {
239 match msg_comps.next() {
240 Some(msg) => match org_comps.next() {
241 Some(org) => {
242 if org == msg {
243 match self.children.get(org) {
244 Some(child) => child.is_match_inner(org_comps, msg_comps),
245 None => false,
246 }
247 } else {
248 false
249 }
250 }
251 None => match self.children.get(msg) {
252 Some(child) => match child.send_inner(msg_comps) {
253 Status::Queue(_) | Status::Dropped | Status::Intro(_) => false,
254 Status::Unhandled(_) => self.handler.get_queue().is_some(),
255 },
256 None => matches!(self.handler, CallHandler::Queue(_)),
257 },
258 },
259 None => match org_comps.next() {
260 Some(_) => false,
261 None => self.handler.get_queue().is_some(),
262 },
263 }
264 }
265 pub fn is_match(&self, org_path: &ObjectPath, msg_path: &ObjectPath) -> bool {
266 let org_comps = org_path.components();
267 let msg_comps = msg_path.components();
268 self.is_match_inner(org_comps, msg_comps)
269 }
270}
271
272fn make_object_not_found(msg: MarshalledMessage) -> MarshalledMessage {
273 msg.dynheader
274 .make_error_response("org.freedesktop.DBus.Error.UnknownObject", None)
275}
276
277const INTRO_START: &str = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">
278 <node>
279\t<interface name=\"org.freedesktop.DBus.Introspectable\">
280\t\t<method name=\"Introspect\">
281\t\t\t<arg name=\"xml_data\" type=\"s\" direction=\"out\"/>
282\t\t</method>
283\t</interface>\n";
284const INTRO_END: &str = " </node>";
285
286fn make_intro_msg(
287 msg: MarshalledMessage,
288 children: Iter<String, CallHierarchy>,
289) -> MarshalledMessage {
290 if msg.dynheader.interface.as_ref().unwrap() == "org.freedesktop.DBus.Introspectable" {
291 let mut res = msg.dynheader.make_response();
292 let mut intro_str = String::from(INTRO_START);
293 let children = children.filter_map(|(s, c)| match c.handler {
294 CallHandler::Drop => None,
295 _ => Some(s),
296 });
297 for child in children {
298 writeln!(intro_str, "\t<node name=\"{}\"/>", child).unwrap();
299 }
300 intro_str.push_str(INTRO_END);
301 res.body.push_param(intro_str).unwrap();
302 res
303 } else {
304 msg.dynheader.make_error_response("UnknownInterface", None)
305 }
306}
307
308#[derive(Default)]
309pub struct MatchRule {
321 pub sender: Option<Arc<str>>,
323 pub path: Option<Arc<str>>,
326 pub path_namespace: Option<Arc<str>>,
330 pub interface: Option<Arc<str>>,
332 pub member: Option<Arc<str>>,
334 pub(super) queue: Option<MsgQueue>,
335}
336
337pub const EMPTY_MATCH: &MatchRule = &MatchRule {
340 sender: None,
341 path: None,
342 path_namespace: None,
343 interface: None,
344 member: None,
345 queue: None,
346};
347impl Debug for MatchRule {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 let mut ds = f.debug_struct("MatchRule");
350 ds.field("sender", &self.sender);
351 ds.field("path", &self.path);
352 ds.field("path_namespace", &self.path_namespace);
353 ds.field("interface", &self.interface);
354 ds.field("member", &self.member);
355 struct EmptyPrintable;
356 impl Debug for EmptyPrintable {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 write!(f, "_")
359 }
360 }
361 ds.field("queue", &self.queue.as_ref().map(|_| EmptyPrintable));
362 ds.finish()
363 }
364}
365impl Clone for MatchRule {
366 fn clone(&self) -> Self {
367 Self {
368 sender: self.sender.clone(),
369 path: self.path.clone(),
370 path_namespace: self.path_namespace.clone(),
371 interface: self.interface.clone(),
372 member: self.member.clone(),
373 queue: None,
374 }
375 }
376}
377impl MatchRule {
378 pub fn new() -> Self {
379 Self::default()
380 }
381 pub fn sender<S: Into<String>>(&mut self, sender: S) -> &mut Self {
382 self.sender = Some(sender.into().into());
383 self
384 }
385 pub fn path<S: Into<String>>(&mut self, path: S) -> &mut Self {
386 self.path = Some(path.into().into());
387 self.path_namespace = None; self
389 }
390 pub fn path_namespace<S: Into<String>>(&mut self, path_namespace: S) -> &mut Self {
391 self.path_namespace = Some(path_namespace.into().into());
392 self.path = None;
393 self
394 }
395 pub fn interface<S: Into<String>>(&mut self, interface: S) -> &mut Self {
396 self.interface = Some(interface.into().into());
397 self
398 }
399 pub fn member<S: Into<String>>(&mut self, member: S) -> &mut Self {
400 self.member = Some(member.into().into());
401 self
402 }
403 pub fn is_empty(&self) -> bool {
404 EMPTY_MATCH == self
405 }
406 pub fn matches(&self, msg: &MarshalledMessage) -> bool {
408 if !matches!(msg.typ, MessageType::Signal) {
409 return false;
410 }
411 match (&self.sender, &msg.dynheader.sender) {
412 (Some(ss), Some(ms)) => {
413 if ss.as_ref() != ms {
414 return false;
415 }
416 }
417 (Some(_), None) => return false,
418 (None, _) => {}
419 }
420 match (&self.path, &msg.dynheader.object) {
421 (Some(ss), Some(ms)) => {
422 if ss.as_ref() != ms {
423 return false;
424 }
425 }
426 (Some(_), None) => return false,
427 (None, _) => {}
428 }
429 match (&self.path_namespace, &msg.dynheader.object) {
430 (Some(ss), Some(ms)) => {
431 if !Path::new(ms).starts_with(ss.as_ref()) {
432 return false;
433 }
434 }
435 (Some(_), None) => return false,
436 (None, _) => {}
437 }
438 match (&self.interface, &msg.dynheader.interface) {
439 (Some(ss), Some(ms)) => {
440 if ss.as_ref() != ms {
441 return false;
442 }
443 }
444 (Some(_), None) => return false,
445 (None, _) => {}
446 }
447 match (&self.member, &msg.dynheader.member) {
448 (Some(ss), Some(ms)) => {
449 if ss.as_ref() != ms {
450 return false;
451 }
452 }
453 (Some(_), None) => return false,
454 (None, _) => {}
455 }
456 true
457 }
458 pub fn match_string(&self) -> String {
460 let mut match_str = String::new();
461 if let Some(sender) = &self.sender {
462 match_str.push_str("sender='");
463 match_str.push_str(sender);
464 match_str.push_str("',");
465 }
466 if let Some(path) = &self.path {
467 match_str.push_str("path='");
468 match_str.push_str(path);
469 match_str.push_str("',");
470 }
471 if let Some(path_namespace) = &self.path_namespace {
472 match_str.push_str("path_namespace='");
473 match_str.push_str(path_namespace);
474 match_str.push_str("',");
475 }
476 if let Some(interface) = &self.interface {
477 match_str.push_str("interface='");
478 match_str.push_str(interface);
479 match_str.push_str("',");
480 }
481 if let Some(member) = &self.member {
482 match_str.push_str("member='");
483 match_str.push_str(member);
484 match_str.push_str("',");
485 }
486 match_str.push_str("type='signal'");
487 match_str
488 }
489}
490impl PartialEq<MatchRule> for MatchRule {
491 fn eq(&self, other: &MatchRule) -> bool {
492 if self.sender != other.sender {
493 return false;
494 }
495 if self.path != other.path {
496 return false;
497 }
498 if self.path != other.path {
499 return false;
500 }
501 if self.path_namespace != other.path_namespace {
502 return false;
503 }
504 if self.interface != other.interface {
505 return false;
506 }
507 if self.member != other.member {
508 return false;
509 }
510 true
511 }
512}
513impl Eq for MatchRule {}
514fn option_ord<T>(left: &Option<T>, right: &Option<T>) -> Option<COrdering> {
515 match &left {
516 Some(_) => {
517 if right.is_none() {
518 return Some(COrdering::Less);
519 }
520 }
521 None => {
522 if right.is_some() {
523 return Some(COrdering::Greater);
524 }
525 }
526 }
527 None
528}
529fn path_subset(left: &Option<Arc<str>>, right: &Option<Arc<str>>) -> Option<COrdering> {
530 if let Some(ord) = option_ord(left, right) {
531 return Some(ord);
532 }
533 let mut l_path = match &left {
534 Some(p) => Path::new(p.as_ref()).components(),
535 None => return None,
536 };
537 let mut r_path = Path::new(right.as_ref().unwrap().as_ref()).components();
538 loop {
539 break match (l_path.next(), r_path.next()) {
540 (Some(l_comp), Some(r_comp)) => {
541 if l_comp == r_comp {
542 continue;
543 } else {
544 None
545 }
546 }
547 (Some(_), None) => Some(COrdering::Less),
548 (None, Some(_)) => Some(COrdering::Greater),
549 (None, None) => None,
550 };
551 }
552}
553impl Ord for MatchRule {
578 fn cmp(&self, other: &Self) -> COrdering {
579 if let Some(ord) = option_ord(&self.sender, &other.sender) {
582 return ord;
583 }
584 if let Some(ord) = option_ord(&self.path, &other.path) {
585 return ord;
586 }
587 if let Some(ord) = path_subset(&self.path_namespace, &other.path_namespace) {
588 return ord;
589 }
590 if let Some(ord) = option_ord(&self.interface, &other.interface) {
591 return ord;
592 }
593 if let Some(ord) = option_ord(&self.member, &other.member) {
594 return ord;
595 }
596 self.sender
597 .cmp(&other.sender)
598 .then_with(|| self.path.cmp(&other.path))
599 .then_with(|| self.path_namespace.cmp(&other.path_namespace))
600 .then_with(|| self.interface.cmp(&other.interface))
601 .then_with(|| self.member.cmp(&other.member))
602 }
603}
604impl PartialOrd<MatchRule> for MatchRule {
605 fn partial_cmp(&self, other: &MatchRule) -> Option<COrdering> {
606 Some(self.cmp(other))
607 }
608}
609
610pub fn queue_sig(sig_matches: &[MatchRule], sig: MarshalledMessage) {
611 for sig_match in sig_matches {
612 if sig_match.matches(&sig) {
613 sig_match.queue.as_ref().unwrap().send(sig);
614 return;
615 }
616 }
617}
618
619#[cfg(test)]
620mod tests {
621 use super::rustbus_core;
622 use super::{CallAction, CallHierarchy, MatchRule, MsgQueue, EMPTY_MATCH};
623 use std::convert::TryInto;
624
625 #[test]
626 fn call_hierarchy_insert() {
627 let mut hierarchy = CallHierarchy::new();
628 hierarchy.insert_path("/usr/local/bin".try_into().unwrap(), CallAction::Queue);
629 assert_eq!(
630 hierarchy
631 .get_action("/usr/local/bin".try_into().unwrap())
632 .unwrap(),
633 CallAction::Queue
634 );
635 assert_eq!(
636 hierarchy
637 .get_action("/usr/local".try_into().unwrap())
638 .unwrap(),
639 CallAction::Nothing
640 );
641 assert_eq!(
642 hierarchy.get_action("/usr".try_into().unwrap()).unwrap(),
643 CallAction::Nothing
644 );
645 assert_eq!(
646 hierarchy.get_action("/".try_into().unwrap()).unwrap(),
647 CallAction::Drop
648 );
649 assert!(hierarchy.is_match(
650 "/usr/local/bin".try_into().unwrap(),
651 "/usr/local/bin/echo".try_into().unwrap()
652 ));
653 assert!(hierarchy.is_match(
654 "/usr/local/bin".try_into().unwrap(),
655 "/usr/local/bin".try_into().unwrap()
656 ));
657 assert!(!hierarchy.is_match(
658 "/usr/local".try_into().unwrap(),
659 "/usr/local".try_into().unwrap()
660 ));
661 assert!(!hierarchy.is_match("/usr".try_into().unwrap(), "/usr/local".try_into().unwrap()));
662 assert!(!hierarchy.is_match(
663 "/".try_into().unwrap(),
664 "/usr/local/bin".try_into().unwrap()
665 ));
666 assert!(!hierarchy.is_match("/".try_into().unwrap(), "/usr/local".try_into().unwrap()));
667 hierarchy.insert_path("/".try_into().unwrap(), CallAction::Queue);
668 assert!(hierarchy.is_match("/".try_into().unwrap(), "/usr/local".try_into().unwrap()));
669 hierarchy.insert_path("/var".try_into().unwrap(), CallAction::Exact);
670 hierarchy.insert_path("/var/log/journal".try_into().unwrap(), CallAction::Queue);
671 assert!(hierarchy.is_match(
672 "/var/log/journal".try_into().unwrap(),
673 "/var/log/journal".try_into().unwrap()
674 ));
675 assert!(hierarchy.is_match("/var".try_into().unwrap(), "/var/log".try_into().unwrap()));
676 assert!(!hierarchy.is_match("/".try_into().unwrap(), "/var/log".try_into().unwrap()));
677 assert!(!hierarchy.is_match("/".try_into().unwrap(), "/var".try_into().unwrap()));
678 }
679 #[test]
680 fn trimming() {
681 let mut hierarchy = CallHierarchy::new();
682 hierarchy.insert_path("/usr/local/bin".try_into().unwrap(), CallAction::Queue);
683 hierarchy.insert_path(
684 "/usr/local/bin/hello/find".try_into().unwrap(),
685 CallAction::Queue,
686 );
687 hierarchy.insert_path(
688 "/usr/local/bin/hello/find".try_into().unwrap(),
689 CallAction::Nothing,
690 );
691 hierarchy.insert_path("/usr/local/bin".try_into().unwrap(), CallAction::Nothing);
692 println!("{:#?}", hierarchy);
693 assert!(hierarchy.children.is_empty());
694 hierarchy.insert_path("/usr/local/bin".try_into().unwrap(), CallAction::Queue);
695 hierarchy.insert_path(
696 "/usr/local/bin/hello/find".try_into().unwrap(),
697 CallAction::Queue,
698 );
699 hierarchy.insert_path("/usr/local/bin".try_into().unwrap(), CallAction::Nothing);
700 hierarchy.insert_path(
701 "/usr/local/bin/hello/find".try_into().unwrap(),
702 CallAction::Nothing,
703 );
704 assert!(hierarchy.children.is_empty());
705 }
706
707 #[test]
708 fn match_order() {
709 use rand::seq::SliceRandom;
710 use rand::thread_rng;
711 let mut w_sender = MatchRule::new();
712 w_sender.sender("org.freedesktop.DBus");
713 let mut w_path = MatchRule::new();
714 w_path.path("/hello");
715 let mut w_namespace0 = MatchRule::new();
716 w_namespace0.path_namespace("/org");
717 let mut w_namespace1 = MatchRule::new();
718 w_namespace1.path_namespace("/org/freedesktop");
719 let mut w_interface = MatchRule::new();
720 w_interface.interface("org.freedesktop.DBus");
721 let mut w_member = MatchRule::new();
722 w_member.member("Peer");
723 let mut array = [
724 &w_sender,
725 &w_path,
726 &w_namespace0,
727 &w_namespace1,
728 &w_interface,
729 &w_member,
730 ];
731 let mut rng = thread_rng();
732 array.shuffle(&mut rng);
733 array.sort_unstable();
734 assert!(std::ptr::eq(&w_sender, array[0]));
735 assert!(std::ptr::eq(&w_path, array[1]));
736 assert!(std::ptr::eq(&w_namespace1, array[2]));
737 assert!(std::ptr::eq(&w_namespace0, array[3]));
738 assert!(std::ptr::eq(&w_interface, array[4]));
739 assert!(std::ptr::eq(&w_member, array[5]));
740 }
741 use rustbus_core::message_builder::MessageBuilder;
742 #[test]
743 fn matches_single() {
744 let m1 = MatchRule::new().interface("io.test.Test1").clone();
745 let mut m1_q = m1.clone();
746 m1_q.queue = Some(MsgQueue::new());
747
748 let m2 = MatchRule::new().member("TestSig1").clone();
749 let mut m2_q = m2.clone();
750 m2_q.queue = Some(MsgQueue::new());
751
752 let mut m3 = m2.clone();
753 m3.interface = m1.interface.clone();
754 let mut m3_q = m3.clone();
755 m3_q.queue = Some(MsgQueue::new());
756
757 let m4 = MatchRule::new().path_namespace("/io/test").clone();
758 let mut m4_q = m4.clone();
759 m4_q.queue = Some(MsgQueue::new());
760
761 let m5 = MatchRule::new().path("/io/test/specific").clone();
762 let mut m5_q = m5.clone();
763 m5_q.queue = Some(MsgQueue::new());
764
765 let m6 = MatchRule::new().sender("io.test_sender").clone();
766 let mut m6_q = m6.clone();
767 m6_q.queue = Some(MsgQueue::new());
768
769 let mut msg = MessageBuilder::new()
770 .signal("io.test.Test1", "TestSig1", "/")
771 .build();
772 msg.dynheader.sender = Some("io.other".into());
773
774 assert!(EMPTY_MATCH.matches(&msg));
775 assert!(m1.matches(&msg));
776 assert!(m1_q.matches(&msg));
777 assert!(m2.matches(&msg));
778 assert!(m2_q.matches(&msg));
779 assert!(m3.matches(&msg));
780 assert!(m3_q.matches(&msg));
781 assert!(!m4.matches(&msg));
782 assert!(!m4_q.matches(&msg));
783 assert!(!m5.matches(&msg));
784 assert!(!m5_q.matches(&msg));
785 assert!(!m6.matches(&msg));
786 assert!(!m6_q.matches(&msg));
787
788 let mut other_if = Some("io.test.Test2".to_string());
789 std::mem::swap(&mut msg.dynheader.interface, &mut other_if);
790 assert!(!m1.matches(&msg));
791 assert!(!m1_q.matches(&msg));
792 assert!(m2.matches(&msg));
793 assert!(m2_q.matches(&msg));
794 assert!(!m3.matches(&msg));
795 assert!(!m3_q.matches(&msg));
796 std::mem::swap(&mut msg.dynheader.interface, &mut other_if);
797
798 msg.dynheader.member = Some("TestSig2".into());
799 assert!(m1.matches(&msg));
800 assert!(m1_q.matches(&msg));
801 assert!(!m2.matches(&msg));
802 assert!(!m2_q.matches(&msg));
803 assert!(!m3.matches(&msg));
804 assert!(!m3_q.matches(&msg));
805
806 msg.dynheader.object = Some("/io/test".into());
807 assert!(m4.matches(&msg));
808 assert!(m4_q.matches(&msg));
809 assert!(!m5.matches(&msg));
810 assert!(!m5_q.matches(&msg));
811
812 msg.dynheader.object = Some("/io/test/specific".into());
813 assert!(m4.matches(&msg));
814 assert!(m4_q.matches(&msg));
815 assert!(m5.matches(&msg));
816 assert!(m5_q.matches(&msg));
817
818 msg.dynheader.object = Some("/io/test/specific/too".into());
819 assert!(m4.matches(&msg));
820 assert!(m4_q.matches(&msg));
821 assert!(!m5.matches(&msg));
822 assert!(!m5_q.matches(&msg));
823
824 msg.dynheader.sender = Some("io.test_sender".into());
825 assert!(m6.matches(&msg));
826 assert!(m6_q.matches(&msg));
827 assert!(EMPTY_MATCH.matches(&msg));
828 }
829 #[test]
830 fn matches_is_empty() {
831 assert!(EMPTY_MATCH.is_empty());
832 let mut me_q = MatchRule::new();
833 me_q.queue = Some(MsgQueue::new());
834 assert!(me_q.is_empty());
835 }
836}