1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use super::MatchRule;
use crate::{
    message::Message,
    value::{Bus, Value},
};

fn match_namespace<const P: char>(namespace: &str, value: &str) -> bool {
    if let Some(value) = value.strip_prefix(namespace) {
        value.starts_with(P) || value.is_empty()
    } else {
        false
    }
}

fn get_str_from_string_or_object_path(value: &Value) -> Option<&str> {
    match value {
        Value::String(string) => Some(string),
        Value::ObjectPath(object_path) => Some(object_path.as_ref()),
        _ => None,
    }
}

impl MatchRule {
    pub fn matching_rule(&self, message: &Message) -> bool {
        match self {
            MatchRule::Type(r#type) => r#type == &message.get_type(),
            MatchRule::Sender(sender_1) => {
                if let Some(sender_2) = message.get_sender() {
                    sender_1 == sender_2
                } else {
                    false
                }
            }
            MatchRule::Interface(interface_1) => {
                if let Some(interface_2) = message.get_interface() {
                    interface_1 == interface_2
                } else {
                    false
                }
            }
            MatchRule::Member(member_1) => {
                if let Some(member_2) = message.get_member() {
                    member_1 == member_2
                } else {
                    false
                }
            }
            MatchRule::Path(path_1) => {
                if let Some(path_2) = message.get_path() {
                    path_1 == path_2
                } else {
                    false
                }
            }
            MatchRule::PathNamespace(path_namespace) => {
                if let Some(path) = message.get_path() {
                    match_namespace::<'/'>(path_namespace.as_ref(), path.as_ref())
                } else {
                    false
                }
            }
            MatchRule::Destination(destination_1) => {
                if let Some(destination_2) = message.get_destination() {
                    match destination_2 {
                        Bus::WellKnownBusName(_) => false,
                        Bus::UniqueConnectionName(destination_2) => destination_1 == destination_2,
                    }
                } else {
                    false
                }
            }
            MatchRule::Arg(arg) => {
                let body = message.get_body();
                if let Some(Value::String(value)) = body.get(arg.get_index()) {
                    arg.get_value() == value
                } else {
                    false
                }
            }
            MatchRule::ArgPath(arg_path) => {
                let body = message.get_body();
                if let Some(value) = body.get(arg_path.get_index()) {
                    if let Some(string) = get_str_from_string_or_object_path(value) {
                        match_namespace::<'/'>(arg_path.get_value().as_ref(), string)
                    } else {
                        false
                    }
                } else {
                    false
                }
            }
            MatchRule::Arg0Namespace(arg0_namespace) => {
                let body = message.get_body();
                if let Some(Value::String(arg0)) = body.get(0) {
                    match_namespace::<'.'>(arg0_namespace.as_ref(), arg0)
                } else {
                    false
                }
            }
            MatchRule::Eavesdrop(_) => true,
        }
    }

    pub fn matching_rules(match_rules: &[MatchRule], message: &Message) -> bool {
        for match_rule in match_rules.iter() {
            if !match_rule.matching_rule(message) {
                return false;
            }
        }
        true
    }
}