zbus/match_rule/
builder.rs1use crate::{
2 match_rule::PathSpec,
3 message::Type,
4 names::{BusName, InterfaceName, MemberName, UniqueName},
5 zvariant::{ObjectPath, Str},
6 Error, MatchRule, Result,
7};
8
9const MAX_ARGS: u8 = 64;
10
11#[derive(Debug)]
15pub struct Builder<'m>(MatchRule<'m>);
16
17impl<'m> Builder<'m> {
18 pub fn build(self) -> MatchRule<'m> {
20 self.0
21 }
22
23 pub fn sender<B>(mut self, sender: B) -> Result<Self>
25 where
26 B: TryInto<BusName<'m>>,
27 B::Error: Into<Error>,
28 {
29 self.0.sender = Some(sender.try_into().map_err(Into::into)?);
30
31 Ok(self)
32 }
33
34 pub fn msg_type(mut self, msg_type: Type) -> Self {
36 self.0.msg_type = Some(msg_type);
37
38 self
39 }
40
41 pub fn interface<I>(mut self, interface: I) -> Result<Self>
43 where
44 I: TryInto<InterfaceName<'m>>,
45 I::Error: Into<Error>,
46 {
47 self.0.interface = Some(interface.try_into().map_err(Into::into)?);
48
49 Ok(self)
50 }
51
52 pub fn member<M>(mut self, member: M) -> Result<Self>
54 where
55 M: TryInto<MemberName<'m>>,
56 M::Error: Into<Error>,
57 {
58 self.0.member = Some(member.try_into().map_err(Into::into)?);
59
60 Ok(self)
61 }
62
63 pub fn path<P>(mut self, path: P) -> Result<Self>
68 where
69 P: TryInto<ObjectPath<'m>>,
70 P::Error: Into<Error>,
71 {
72 self.0.path_spec = path
73 .try_into()
74 .map(PathSpec::Path)
75 .map(Some)
76 .map_err(Into::into)?;
77
78 Ok(self)
79 }
80
81 pub fn path_namespace<P>(mut self, path_namespace: P) -> Result<Self>
86 where
87 P: TryInto<ObjectPath<'m>>,
88 P::Error: Into<Error>,
89 {
90 self.0.path_spec = path_namespace
91 .try_into()
92 .map(PathSpec::PathNamespace)
93 .map(Some)
94 .map_err(Into::into)?;
95
96 Ok(self)
97 }
98
99 pub fn destination<B>(mut self, destination: B) -> Result<Self>
101 where
102 B: TryInto<UniqueName<'m>>,
103 B::Error: Into<Error>,
104 {
105 self.0.destination = Some(destination.try_into().map_err(Into::into)?);
106
107 Ok(self)
108 }
109
110 pub fn add_arg<S>(self, arg: S) -> Result<Self>
118 where
119 S: Into<Str<'m>>,
120 {
121 let idx = self.0.args.len() as u8;
122
123 self.arg(idx, arg)
124 }
125
126 pub fn arg<S>(mut self, idx: u8, arg: S) -> Result<Self>
132 where
133 S: Into<Str<'m>>,
134 {
135 if idx >= MAX_ARGS {
136 return Err(Error::InvalidMatchRule);
137 }
138 let value = (idx, arg.into());
139 let vec_idx = match self.0.args().binary_search_by(|(i, _)| i.cmp(&idx)) {
140 Ok(i) => {
141 self.0.args.remove(i);
143
144 i
145 }
146 Err(i) => i,
147 };
148 self.0.args.insert(vec_idx, value);
149
150 Ok(self)
151 }
152
153 pub fn add_arg_path<P>(self, arg_path: P) -> Result<Self>
161 where
162 P: TryInto<ObjectPath<'m>>,
163 P::Error: Into<Error>,
164 {
165 let idx = self.0.arg_paths.len() as u8;
166
167 self.arg_path(idx, arg_path)
168 }
169
170 pub fn arg_path<P>(mut self, idx: u8, arg_path: P) -> Result<Self>
176 where
177 P: TryInto<ObjectPath<'m>>,
178 P::Error: Into<Error>,
179 {
180 if idx >= MAX_ARGS {
181 return Err(Error::InvalidMatchRule);
182 }
183
184 let value = (idx, arg_path.try_into().map_err(Into::into)?);
185 let vec_idx = match self.0.arg_paths().binary_search_by(|(i, _)| i.cmp(&idx)) {
186 Ok(i) => {
187 self.0.arg_paths.remove(i);
189
190 i
191 }
192 Err(i) => i,
193 };
194 self.0.arg_paths.insert(vec_idx, value);
195
196 Ok(self)
197 }
198
199 pub fn arg0ns<S>(mut self, namespace: S) -> Result<Self>
222 where
223 S: Into<Str<'m>>,
224 {
225 let namespace: Str<'m> = namespace.into();
226
227 if namespace.is_empty() || namespace.len() > 255 {
231 return Err(Error::InvalidMatchRule);
232 }
233
234 let (is_unique, namespace_str) = match namespace.strip_prefix(':') {
235 Some(s) => (true, s),
236 None => (false, namespace.as_str()),
237 };
238
239 let valid_first_char = |s: &str| match s.chars().next() {
240 None | Some('.') => false,
241 Some('0'..='9') if !is_unique => false,
242 _ => true,
243 };
244
245 if !valid_first_char(namespace_str)
246 || !namespace_str.split('.').all(valid_first_char)
247 || !namespace_str
248 .chars()
249 .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.')
250 {
251 return Err(Error::InvalidMatchRule);
252 }
253
254 self.0.arg0ns = Some(namespace);
255
256 Ok(self)
257 }
258
259 pub(crate) fn new() -> Self {
261 Self(MatchRule {
262 msg_type: None,
263 sender: None,
264 interface: None,
265 member: None,
266 path_spec: None,
267 destination: None,
268 args: Vec::with_capacity(MAX_ARGS as usize),
269 arg_paths: Vec::with_capacity(MAX_ARGS as usize),
270 arg0ns: None,
271 })
272 }
273}