1use std::{borrow::Borrow, collections::HashMap, marker::PhantomData};
2
3use serde::{Deserialize, Serialize};
4use zvariant::{Signature, Type};
5
6use crate::{Interface, InterfaceSet, Role, State, StateSet};
7
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Type)]
11#[repr(u32)]
12pub enum TreeTraversalType {
13 RestrictChildren,
15
16 RestrictSibling,
18
19 #[default]
21 Inorder,
22}
23
24#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
34pub struct ObjectMatchRule {
35 pub states: StateSet,
36 pub states_mt: MatchType,
37 pub attr: HashMap<String, String>,
38 pub attr_mt: MatchType,
39 pub roles: Vec<Role>,
40 pub roles_mt: MatchType,
41 pub ifaces: InterfaceSet,
42 pub ifaces_mt: MatchType,
43 pub invert: bool,
44 #[serde(skip)]
47 _marker: std::marker::PhantomData<()>,
48}
49
50impl Type for ObjectMatchRule {
63 const SIGNATURE: &'static Signature = &Signature::static_structure(&[
64 <Vec<i32>>::SIGNATURE,
65 &Signature::I32,
66 <HashMap<&str, &str>>::SIGNATURE,
67 &Signature::I32,
68 <Vec<i32>>::SIGNATURE,
69 &Signature::I32,
70 <Vec<&str>>::SIGNATURE,
71 &Signature::I32,
72 &Signature::Bool,
73 ]);
74}
75
76impl ObjectMatchRule {
77 #[must_use]
79 pub fn builder() -> ObjectMatchRuleBuilder {
80 ObjectMatchRuleBuilder::default()
81 }
82}
83
84#[derive(Debug, Clone, Default)]
87pub struct ObjectMatchRuleBuilder {
88 states: StateSet,
89 states_mt: MatchType,
90 attr: HashMap<String, String>,
91 attr_mt: MatchType,
92 roles: Vec<Role>,
93 roles_mt: MatchType,
94 ifaces: InterfaceSet,
95 ifaces_mt: MatchType,
96 invert: bool,
97}
98
99impl ObjectMatchRuleBuilder {
100 #[must_use]
102 pub fn states<I>(mut self, states: I, mt: MatchType) -> Self
103 where
104 I: IntoIterator,
105 I::Item: Borrow<State>,
106 {
107 self.states = states.into_iter().map(|state| *state.borrow()).collect();
108 self.states_mt = mt;
109 self
110 }
111
112 #[must_use]
114 pub fn attributes(mut self, attributes: HashMap<String, String>, mt: MatchType) -> Self {
115 self.attr = attributes;
116 self.attr_mt = mt;
117 self
118 }
119
120 #[must_use]
122 pub fn roles(mut self, roles: &[Role], mt: MatchType) -> Self {
123 self.roles = roles.into();
124 self.roles_mt = mt;
125 self
126 }
127
128 #[must_use]
130 pub fn interfaces<I>(mut self, interfaces: I, mt: MatchType) -> Self
131 where
132 I: IntoIterator,
133 I::Item: Borrow<Interface>,
134 {
135 self.ifaces = interfaces.into_iter().map(|iface| *iface.borrow()).collect();
136 self.ifaces_mt = mt;
137 self
138 }
139
140 #[must_use]
142 pub fn invert(mut self, invert: bool) -> Self {
143 self.invert = invert;
144 self
145 }
146
147 #[must_use]
151 pub fn build(self) -> ObjectMatchRule {
152 ObjectMatchRule {
153 states: self.states,
154 states_mt: self.states_mt,
155 attr: self.attr,
156 attr_mt: self.attr_mt,
157 roles: self.roles,
158 roles_mt: self.roles_mt,
159 ifaces: self.ifaces,
160 ifaces_mt: self.ifaces_mt,
161 invert: self.invert,
162 _marker: PhantomData,
163 }
164 }
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type, Default)]
171#[repr(i32)]
172pub enum MatchType {
173 Invalid,
175
176 #[default]
177 All,
179
180 Any,
182
183 NA,
185
186 Empty,
189}
190
191#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)]
192#[repr(u32)]
193pub enum SortOrder {
204 Invalid,
208
209 Canonical,
211
212 Flow,
216
217 Tab,
221
222 ReverseCanonical,
224
225 ReverseFlow,
229
230 ReverseTab,
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239 use crate::{SortOrder, State};
240 use std::str::FromStr;
241 use zbus_lockstep::method_args_signature;
242
243 #[test]
244 fn validate_match_rule_signature() {
245 let signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "rule");
246 assert_eq!(*<ObjectMatchRule as Type>::SIGNATURE, signature);
247 }
248
249 #[test]
250 fn validate_match_type_signature() {
251 let rule_signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "rule");
252 let match_type_signature_str = rule_signature.to_string();
254 let match_type_signature = Signature::from_str(&match_type_signature_str.as_str()[3..4])
255 .expect("Valid signature pattern");
256 assert_eq!(*<MatchType as Type>::SIGNATURE, match_type_signature);
257 }
258
259 #[test]
260 fn validate_tree_traversal_type_signature() {
261 let signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "tree");
262 assert_eq!(*<TreeTraversalType as Type>::SIGNATURE, signature);
263 }
264
265 #[test]
266 fn validate_sort_order_signature() {
267 let signature = method_args_signature!(member: "GetMatches", interface: "org.a11y.atspi.Collection", argument: "sortby");
268 assert_eq!(*<SortOrder as Type>::SIGNATURE, signature);
269 }
270
271 #[test]
272 fn create_empty_object_match_rule() {
273 let rule = ObjectMatchRule::builder().build();
274
275 assert_eq!(rule.states, StateSet::default());
276 assert_eq!(rule.attr, HashMap::new());
277 assert_eq!(rule.roles, Vec::new());
278 assert_eq!(rule.ifaces, InterfaceSet::default());
279 assert!(!rule.invert);
280 }
281
282 #[test]
283 fn create_object_match_rule() {
284 let rule = ObjectMatchRule::builder()
285 .states(StateSet::new(State::Active), MatchType::All)
286 .attributes(
287 [("name".to_string(), "value".to_string())].iter().cloned().collect(),
288 MatchType::Any,
289 )
290 .roles(&[Role::Alert], MatchType::All)
291 .interfaces([Interface::Action], MatchType::Any)
292 .invert(true)
293 .build();
294
295 assert_eq!(rule.states, StateSet::new(State::Active));
296 assert_eq!(
297 rule.attr,
298 [("name".to_string(), "value".to_string())].iter().cloned().collect()
299 );
300 assert_eq!(rule.roles, vec![Role::Alert]);
301 assert_eq!(rule.ifaces, InterfaceSet::new(Interface::Action));
302 assert!(rule.invert);
303 }
304}