tangled
alpha
login
or
join now
bwc9876.dev
/
nu_plugin_dbus
1
fork
atom
Nushell plugin for interacting with D-Bus
1
fork
atom
overview
issues
pulls
pipelines
implement clippy, formatting suggestions
Devyn Cairns
2 years ago
6ce2ffb8
b250d052
+795
-515
7 changed files
expand all
collapse all
unified
split
src
client.rs
config.rs
convert.rs
dbus_type.rs
introspection.rs
main.rs
pattern.rs
+146
-86
src/client.rs
···
1
1
-
use dbus::{channel::{Channel, BusType}, Message, arg::messageitem::MessageItem};
1
1
+
use dbus::{
2
2
+
arg::messageitem::MessageItem,
3
3
+
channel::{BusType, Channel},
4
4
+
Message,
5
5
+
};
2
6
use nu_plugin::LabeledError;
3
7
use nu_protocol::{Spanned, Value};
4
8
5
5
-
use crate::{config::{DbusClientConfig, DbusBusChoice}, dbus_type::DbusType, convert::to_message_item, introspection::Node, pattern::Pattern};
9
9
+
use crate::{
10
10
+
config::{DbusBusChoice, DbusClientConfig},
11
11
+
convert::to_message_item,
12
12
+
dbus_type::DbusType,
13
13
+
introspection::Node,
14
14
+
pattern::Pattern,
15
15
+
};
6
16
7
17
/// Executes D-Bus actions on a connection, handling nushell types
8
18
pub struct DbusClient {
···
12
22
13
23
// Convenience macros for error handling
14
24
macro_rules! validate_with {
15
15
-
($type:ty, $spanned:expr) => (<$type>::new(&$spanned.item).map_err(|msg| {
16
16
-
LabeledError {
25
25
+
($type:ty, $spanned:expr) => {
26
26
+
<$type>::new(&$spanned.item).map_err(|msg| LabeledError {
17
27
label: msg,
18
28
msg: "this argument is incorrect".into(),
19
29
span: Some($spanned.span),
20
20
-
}
21
21
-
}))
30
30
+
})
31
31
+
};
22
32
}
23
33
24
34
impl DbusClient {
···
33
43
ch.register()?;
34
44
Ok(ch)
35
45
}),
36
36
-
}.map_err(|err| {
37
37
-
LabeledError {
38
38
-
label: err.to_string(),
39
39
-
msg: "while connecting to D-Bus as specified here".into(),
40
40
-
span: Some(config.bus_choice.span),
41
41
-
}
46
46
+
}
47
47
+
.map_err(|err| LabeledError {
48
48
+
label: err.to_string(),
49
49
+
msg: "while connecting to D-Bus as specified here".into(),
50
50
+
span: Some(config.bus_choice.span),
42
51
})?;
43
52
Ok(DbusClient {
44
53
config,
45
45
-
conn: channel
54
54
+
conn: channel,
46
55
})
47
56
}
48
57
···
50
59
LabeledError {
51
60
label: err.to_string(),
52
61
msg: msg.to_string(),
53
53
-
span: Some(self.config.span)
62
62
+
span: Some(self.config.span),
54
63
}
55
64
}
56
65
···
69
78
valid_dest,
70
79
valid_object,
71
80
"org.freedesktop.DBus.Introspectable",
72
72
-
"Introspect"
73
73
-
).map_err(|err| self.error(err, context))?;
81
81
+
"Introspect",
82
82
+
)
83
83
+
.map_err(|err| self.error(err, context))?;
74
84
75
85
// Send and get the response
76
76
-
let resp = self.conn.send_with_reply_and_block(message, self.config.timeout.item)
86
86
+
let resp = self
87
87
+
.conn
88
88
+
.send_with_reply_and_block(message, self.config.timeout.item)
77
89
.map_err(|err| self.error(err, context))?;
78
90
79
91
// Parse it to a Node
80
80
-
let xml: &str = resp.get1()
92
92
+
let xml: &str = resp
93
93
+
.get1()
81
94
.ok_or_else(|| self.error("Introspect method returned the wrong type", context))?;
82
95
83
96
Node::from_xml(xml).map_err(|err| self.error(err, context))
···
95
108
96
109
if let Some(sig) = node.get_method_args_signature(&interface.item, &method.item) {
97
110
DbusType::parse_all(&sig).map_err(|err| LabeledError {
98
98
-
label: format!("while getting interface {:?} method {:?} signature: {}",
99
99
-
interface.item,
100
100
-
method.item,
101
101
-
err),
111
111
+
label: format!(
112
112
+
"while getting interface {:?} method {:?} signature: {}",
113
113
+
interface.item, method.item, err
114
114
+
),
102
115
msg: "try running with --no-introspect or --signature".into(),
103
116
span: Some(self.config.span),
104
117
})
···
122
135
let node = self.introspect(dest, object)?;
123
136
124
137
if let Some(sig) = node.get_property_signature(&interface.item, &property.item) {
125
125
-
DbusType::parse_all(&sig).map_err(|err| LabeledError {
126
126
-
label: format!("while getting interface {:?} property {:?} signature: {}",
127
127
-
interface.item,
128
128
-
property.item,
129
129
-
err),
138
138
+
DbusType::parse_all(sig).map_err(|err| LabeledError {
139
139
+
label: format!(
140
140
+
"while getting interface {:?} property {:?} signature: {}",
141
141
+
interface.item, property.item, err
142
142
+
),
130
143
msg: "try running with --no-introspect or --signature".into(),
131
144
span: Some(self.config.span),
132
145
})
133
146
} else {
134
147
Err(LabeledError {
135
135
-
label: format!("Property {:?} not found on {:?}", property.item, interface.item),
148
148
+
label: format!(
149
149
+
"Property {:?} not found on {:?}",
150
150
+
property.item, interface.item
151
151
+
),
136
152
msg: "check that this property/interface is correct".into(),
137
153
span: Some(property.span),
138
154
})
···
158
174
let valid_method = validate_with!(dbus::strings::Member, method)?;
159
175
160
176
// Parse the signature
161
161
-
let mut valid_signature = signature.map(|s| DbusType::parse_all(&s.item).map_err(|err| {
162
162
-
LabeledError {
163
163
-
label: err,
164
164
-
msg: "in signature specified here".into(),
165
165
-
span: Some(s.span),
166
166
-
}
167
167
-
})).transpose()?;
177
177
+
let mut valid_signature = signature
178
178
+
.map(|s| {
179
179
+
DbusType::parse_all(&s.item).map_err(|err| LabeledError {
180
180
+
label: err,
181
181
+
msg: "in signature specified here".into(),
182
182
+
span: Some(s.span),
183
183
+
})
184
184
+
})
185
185
+
.transpose()?;
168
186
169
187
// If not provided, try introspection (unless disabled)
170
188
if valid_signature.is_none() && self.config.introspect {
171
189
match self.get_method_signature_by_introspection(dest, object, interface, method) {
172
190
Ok(sig) => {
173
191
valid_signature = Some(sig);
174
174
-
},
192
192
+
}
175
193
Err(err) => {
176
176
-
eprintln!("Warning: D-Bus introspection failed on {:?}. \
194
194
+
eprintln!(
195
195
+
"Warning: D-Bus introspection failed on {:?}. \
177
196
Use `--no-introspect` or pass `--signature` to silence this warning. \
178
197
Cause: {}",
179
179
-
object.item,
180
180
-
err.label);
198
198
+
object.item, err.label
199
199
+
);
181
200
}
182
201
}
183
202
}
184
203
185
204
if let Some(sig) = &valid_signature {
186
205
if sig.len() != args.len() {
187
187
-
self.error(format!("expected {} arguments, got {}", sig.len(), args.len()), context);
206
206
+
self.error(
207
207
+
format!("expected {} arguments, got {}", sig.len(), args.len()),
208
208
+
context,
209
209
+
);
188
210
}
189
211
}
190
212
191
213
// Construct the method call message
192
192
-
let mut message = Message::new_method_call(
193
193
-
valid_dest,
194
194
-
valid_object,
195
195
-
valid_interface,
196
196
-
valid_method,
197
197
-
).map_err(|err| self.error(err, context))?;
214
214
+
let mut message =
215
215
+
Message::new_method_call(valid_dest, valid_object, valid_interface, valid_method)
216
216
+
.map_err(|err| self.error(err, context))?;
198
217
199
218
// Convert the args to message items
200
200
-
let sigs_iter = valid_signature.iter().flatten().map(Some).chain(std::iter::repeat(None));
219
219
+
let sigs_iter = valid_signature
220
220
+
.iter()
221
221
+
.flatten()
222
222
+
.map(Some)
223
223
+
.chain(std::iter::repeat(None));
201
224
for (val, sig) in args.iter().zip(sigs_iter) {
202
225
message = message.append1(to_message_item(val, sig)?);
203
226
}
204
227
205
228
// Send it on the channel and get the response
206
206
-
let resp = self.conn.send_with_reply_and_block(message, self.config.timeout.item)
229
229
+
let resp = self
230
230
+
.conn
231
231
+
.send_with_reply_and_block(message, self.config.timeout.item)
207
232
.map_err(|err| self.error(err, context))?;
208
233
209
234
crate::convert::from_message(&resp, self.config.span)
···
224
249
self.call(
225
250
dest,
226
251
object,
227
227
-
&Spanned { item: "org.freedesktop.DBus.Properties".into(), span: self.config.span },
228
228
-
&Spanned { item: "Get".into(), span: self.config.span },
229
229
-
Some(&Spanned { item: "ss".into(), span: self.config.span }),
230
230
-
&[interface_val, property_val]
231
231
-
).map(|val| val.into_iter().nth(0).unwrap_or_default())
252
252
+
&Spanned {
253
253
+
item: "org.freedesktop.DBus.Properties".into(),
254
254
+
span: self.config.span,
255
255
+
},
256
256
+
&Spanned {
257
257
+
item: "Get".into(),
258
258
+
span: self.config.span,
259
259
+
},
260
260
+
Some(&Spanned {
261
261
+
item: "ss".into(),
262
262
+
span: self.config.span,
263
263
+
}),
264
264
+
&[interface_val, property_val],
265
265
+
)
266
266
+
.map(|val| val.into_iter().nth(0).unwrap_or_default())
232
267
}
233
268
234
269
/// Get all D-Bus properties from the given object
···
243
278
self.call(
244
279
dest,
245
280
object,
246
246
-
&Spanned { item: "org.freedesktop.DBus.Properties".into(), span: self.config.span },
247
247
-
&Spanned { item: "GetAll".into(), span: self.config.span },
248
248
-
Some(&Spanned { item: "s".into(), span: self.config.span }),
249
249
-
&[interface_val]
250
250
-
).map(|val| val.into_iter().nth(0).unwrap_or_default())
281
281
+
&Spanned {
282
282
+
item: "org.freedesktop.DBus.Properties".into(),
283
283
+
span: self.config.span,
284
284
+
},
285
285
+
&Spanned {
286
286
+
item: "GetAll".into(),
287
287
+
span: self.config.span,
288
288
+
},
289
289
+
Some(&Spanned {
290
290
+
item: "s".into(),
291
291
+
span: self.config.span,
292
292
+
}),
293
293
+
&[interface_val],
294
294
+
)
295
295
+
.map(|val| val.into_iter().nth(0).unwrap_or_default())
251
296
}
252
297
253
298
/// Set a D-Bus property on the given object
···
267
312
let valid_object = validate_with!(dbus::strings::Path, object)?;
268
313
269
314
// Parse the signature
270
270
-
let mut valid_signature = signature.map(|s| DbusType::parse_all(&s.item).map_err(|err| {
271
271
-
LabeledError {
272
272
-
label: err,
273
273
-
msg: "in signature specified here".into(),
274
274
-
span: Some(s.span),
275
275
-
}
276
276
-
})).transpose()?;
315
315
+
let mut valid_signature = signature
316
316
+
.map(|s| {
317
317
+
DbusType::parse_all(&s.item).map_err(|err| LabeledError {
318
318
+
label: err,
319
319
+
msg: "in signature specified here".into(),
320
320
+
span: Some(s.span),
321
321
+
})
322
322
+
})
323
323
+
.transpose()?;
277
324
278
325
// If not provided, try introspection (unless disabled)
279
326
if valid_signature.is_none() && self.config.introspect {
280
327
match self.get_property_signature_by_introspection(dest, object, interface, property) {
281
328
Ok(sig) => {
282
329
valid_signature = Some(sig);
283
283
-
},
330
330
+
}
284
331
Err(err) => {
285
285
-
eprintln!("Warning: D-Bus introspection failed on {:?}. \
332
332
+
eprintln!(
333
333
+
"Warning: D-Bus introspection failed on {:?}. \
286
334
Use `--no-introspect` or pass `--signature` to silence this warning. \
287
335
Cause: {}",
288
288
-
object.item,
289
289
-
err.label);
336
336
+
object.item, err.label
337
337
+
);
290
338
}
291
339
}
292
340
}
293
341
294
342
if let Some(sig) = &valid_signature {
295
343
if sig.len() != 1 {
296
296
-
self.error(format!(
297
297
-
"expected single object signature, but there are {}", sig.len()), context);
344
344
+
self.error(
345
345
+
format!(
346
346
+
"expected single object signature, but there are {}",
347
347
+
sig.len()
348
348
+
),
349
349
+
context,
350
350
+
);
298
351
}
299
352
}
300
353
···
304
357
valid_object,
305
358
"org.freedesktop.DBus.Properties",
306
359
"Set",
307
307
-
).map_err(|err| self.error(err, context))?
308
308
-
.append2(&interface.item, &property.item)
309
309
-
.append1(
310
310
-
// Box it in a variant as required for property setting
311
311
-
MessageItem::Variant(Box::new(
312
312
-
to_message_item(value, valid_signature.as_ref().map(|s| &s[0]))?))
313
313
-
);
360
360
+
)
361
361
+
.map_err(|err| self.error(err, context))?
362
362
+
.append2(&interface.item, &property.item)
363
363
+
.append1(
364
364
+
// Box it in a variant as required for property setting
365
365
+
MessageItem::Variant(Box::new(to_message_item(
366
366
+
value,
367
367
+
valid_signature.as_ref().map(|s| &s[0]),
368
368
+
)?)),
369
369
+
);
314
370
315
371
// Send it on the channel and get the response
316
316
-
self.conn.send_with_reply_and_block(message, self.config.timeout.item)
372
372
+
self.conn
373
373
+
.send_with_reply_and_block(message, self.config.timeout.item)
317
374
.map_err(|err| self.error(err, context))?;
318
375
319
376
Ok(())
320
377
}
321
378
322
322
-
pub fn list(&self, pattern: Option<&Pattern>)
323
323
-
-> Result<Vec<String>, LabeledError>
324
324
-
{
379
379
+
pub fn list(&self, pattern: Option<&Pattern>) -> Result<Vec<String>, LabeledError> {
325
380
let context = "while listing D-Bus connection names";
326
381
327
382
let message = Message::new_method_call(
328
383
"org.freedesktop.DBus",
329
384
"/org/freedesktop/DBus",
330
385
"org.freedesktop.DBus",
331
331
-
"ListNames"
332
332
-
).map_err(|err| self.error(err, context))?;
386
386
+
"ListNames",
387
387
+
)
388
388
+
.map_err(|err| self.error(err, context))?;
333
389
334
334
-
self.conn.send_with_reply_and_block(message, self.config.timeout.item)
390
390
+
self.conn
391
391
+
.send_with_reply_and_block(message, self.config.timeout.item)
335
392
.map_err(|err| self.error(err, context))
336
393
.and_then(|reply| reply.read1().map_err(|err| self.error(err, context)))
337
394
.map(|names: Vec<String>| {
338
395
// Filter the names by the pattern
339
396
if let Some(pattern) = pattern {
340
340
-
names.into_iter().filter(|name| pattern.is_match(name)).collect()
397
397
+
names
398
398
+
.into_iter()
399
399
+
.filter(|name| pattern.is_match(name))
400
400
+
.collect()
341
401
} else {
342
402
names
343
403
}
+33
-18
src/config.rs
···
1
1
use std::time::Duration;
2
2
3
3
use nu_plugin::{EvaluatedCall, LabeledError};
4
4
-
use nu_protocol::{Spanned, Span};
4
4
+
use nu_protocol::{Span, Spanned};
5
5
6
6
/// General configuration related to the D-Bus client connection
7
7
#[derive(Debug, Clone)]
···
37
37
fn try_from(call: &EvaluatedCall) -> Result<Self, Self::Error> {
38
38
let mut config = DbusClientConfig {
39
39
span: call.head,
40
40
-
bus_choice: Spanned { item: DbusBusChoice::default(), span: call.head },
41
41
-
timeout: Spanned { item: Duration::from_secs(2), span: call.head },
40
40
+
bus_choice: Spanned {
41
41
+
item: DbusBusChoice::default(),
42
42
+
span: call.head,
43
43
+
},
44
44
+
timeout: Spanned {
45
45
+
item: Duration::from_secs(2),
46
46
+
span: call.head,
47
47
+
},
42
48
introspect: true,
43
49
};
44
50
···
51
57
"session" => DbusBusChoice::Session,
52
58
"system" => DbusBusChoice::System,
53
59
"started" => DbusBusChoice::Started,
54
54
-
_ => unreachable!()
60
60
+
_ => unreachable!(),
55
61
};
56
56
-
config.bus_choice = Spanned { item: dest, span: name.span };
62
62
+
config.bus_choice = Spanned {
63
63
+
item: dest,
64
64
+
span: name.span,
65
65
+
};
57
66
}
58
58
-
},
67
67
+
}
59
68
r#type @ ("bus" | "peer") => {
60
69
if let Some(value) = value {
61
70
let address = value.as_str()?;
62
71
let dest = match r#type {
63
72
"bus" => DbusBusChoice::Bus(address.to_owned()),
64
73
"peer" => DbusBusChoice::Peer(address.to_owned()),
65
65
-
_ => unreachable!()
74
74
+
_ => unreachable!(),
75
75
+
};
76
76
+
config.bus_choice = Spanned {
77
77
+
item: dest,
78
78
+
span: value.span(),
66
79
};
67
67
-
config.bus_choice = Spanned { item: dest, span: value.span() };
68
80
}
69
69
-
},
81
81
+
}
70
82
"timeout" => {
71
83
if let Some(value) = value {
72
72
-
let nanos: u64 = value.as_duration()?.try_into().map_err(|_| {
73
73
-
LabeledError {
84
84
+
let nanos: u64 =
85
85
+
value.as_duration()?.try_into().map_err(|_| LabeledError {
74
86
label: "Timeout must be a positive duration".into(),
75
87
msg: "invalid timeout specified here".into(),
76
88
span: Some(value.span()),
77
77
-
}
78
78
-
})?;
89
89
+
})?;
79
90
let item = Duration::from_nanos(nanos);
80
80
-
config.timeout = Spanned { item, span: value.span() };
91
91
+
config.timeout = Spanned {
92
92
+
item,
93
93
+
span: value.span(),
94
94
+
};
81
95
}
82
82
-
},
96
96
+
}
83
97
"no-introspect" => {
84
84
-
config.introspect = !value.as_ref()
98
98
+
config.introspect = !value
99
99
+
.as_ref()
85
100
.and_then(|v| v.as_bool().ok())
86
101
.unwrap_or(false);
87
87
-
},
88
88
-
_ => ()
102
102
+
}
103
103
+
_ => (),
89
104
}
90
105
}
91
106
+175
-118
src/convert.rs
···
1
1
-
use dbus::{Message, arg::{ArgType, RefArg, messageitem::{MessageItemArray, MessageItem, MessageItemDict}}, Signature};
1
1
+
use dbus::{
2
2
+
arg::{
3
3
+
messageitem::{MessageItem, MessageItemArray, MessageItemDict},
4
4
+
ArgType, RefArg,
5
5
+
},
6
6
+
Message, Signature,
7
7
+
};
2
8
use nu_plugin::LabeledError;
3
3
-
use nu_protocol::{Value, Span, Record};
9
9
+
use nu_protocol::{Record, Span, Value};
4
10
use std::str::FromStr;
5
11
6
12
use crate::dbus_type::DbusType;
···
31
37
Value::record(record, span)
32
38
} else if &*refarg.signature() == "ay" {
33
39
// Byte array - better to return as binary
34
34
-
let bytes = dbus::arg::cast::<Vec<u8>>(&refarg.box_clone()).unwrap().to_owned();
40
40
+
let bytes = dbus::arg::cast::<Vec<u8>>(&refarg.box_clone())
41
41
+
.unwrap()
42
42
+
.to_owned();
35
43
Value::binary(bytes, span)
36
44
} else {
37
45
// It's an array
38
46
Value::list(
39
39
-
refarg.as_iter().unwrap().map(|v| from_refarg(v, span)).flatten().collect(),
40
40
-
span)
47
47
+
refarg
48
48
+
.as_iter()
49
49
+
.unwrap()
50
50
+
.flat_map(|v| from_refarg(v, span))
51
51
+
.collect(),
52
52
+
span,
53
53
+
)
41
54
}
42
42
-
},
55
55
+
}
43
56
ArgType::Variant => {
44
44
-
let inner = refarg.as_iter().unwrap().nth(0).unwrap();
57
57
+
let inner = refarg.as_iter().unwrap().next().unwrap();
45
58
return from_refarg(inner, span);
46
46
-
},
47
47
-
ArgType::Boolean =>
48
48
-
Value::bool(refarg.as_i64().unwrap() != 0, span),
59
59
+
}
60
60
+
ArgType::Boolean => Value::bool(refarg.as_i64().unwrap() != 0, span),
49
61
50
62
// Strings
51
51
-
ArgType::String | ArgType::ObjectPath | ArgType::Signature =>
52
52
-
Value::string(refarg.as_str().unwrap(), span),
63
63
+
ArgType::String | ArgType::ObjectPath | ArgType::Signature => {
64
64
+
Value::string(refarg.as_str().unwrap(), span)
65
65
+
}
53
66
// Ints
54
54
-
ArgType::Byte | ArgType::Int16 | ArgType::UInt16 | ArgType::Int32 |
55
55
-
ArgType::UInt32 | ArgType::Int64 | ArgType::UnixFd =>
56
56
-
Value::int(refarg.as_i64().unwrap(), span),
67
67
+
ArgType::Byte
68
68
+
| ArgType::Int16
69
69
+
| ArgType::UInt16
70
70
+
| ArgType::Int32
71
71
+
| ArgType::UInt32
72
72
+
| ArgType::Int64
73
73
+
| ArgType::UnixFd => Value::int(refarg.as_i64().unwrap(), span),
57
74
58
75
// Nushell doesn't support u64, so present it as a string
59
76
ArgType::UInt64 => Value::string(refarg.as_u64().unwrap().to_string(), span),
60
77
61
78
// Floats
62
62
-
ArgType::Double =>
63
63
-
Value::float(refarg.as_f64().unwrap(), span),
79
79
+
ArgType::Double => Value::float(refarg.as_f64().unwrap(), span),
64
80
65
65
-
ArgType::Struct =>
66
66
-
Value::list(
67
67
-
refarg.as_iter().unwrap().map(|v| from_refarg(v, span)).flatten().collect(),
68
68
-
span),
81
81
+
ArgType::Struct => Value::list(
82
82
+
refarg
83
83
+
.as_iter()
84
84
+
.unwrap()
85
85
+
.flat_map(|v| from_refarg(v, span))
86
86
+
.collect(),
87
87
+
span,
88
88
+
),
69
89
70
70
-
ArgType::DictEntry =>
71
71
-
return Err("Encountered dictionary entry outside of dictionary".into()),
72
72
-
ArgType::Invalid =>
73
73
-
return Err("Encountered invalid D-Bus value".into()),
90
90
+
ArgType::DictEntry => {
91
91
+
return Err("Encountered dictionary entry outside of dictionary".into())
92
92
+
}
93
93
+
ArgType::Invalid => return Err("Encountered invalid D-Bus value".into()),
74
94
})
75
95
}
76
96
77
77
-
pub fn to_message_item(value: &Value, expected_type: Option<&DbusType>)
78
78
-
-> Result<MessageItem, LabeledError>
79
79
-
{
97
97
+
pub fn to_message_item(
98
98
+
value: &Value,
99
99
+
expected_type: Option<&DbusType>,
100
100
+
) -> Result<MessageItem, LabeledError> {
80
101
// Report errors from conversion. Error must support Display
81
102
macro_rules! try_convert {
82
82
-
($result_expr:expr) => ($result_expr.map_err(|err| LabeledError {
83
83
-
label: format!("Failed to convert value to the D-Bus `{:?}` type",
84
84
-
expected_type.unwrap()),
85
85
-
msg: err.to_string(),
86
86
-
span: Some(value.span()),
87
87
-
})?)
103
103
+
($result_expr:expr) => {
104
104
+
$result_expr.map_err(|err| LabeledError {
105
105
+
label: format!(
106
106
+
"Failed to convert value to the D-Bus `{:?}` type",
107
107
+
expected_type.unwrap()
108
108
+
),
109
109
+
msg: err.to_string(),
110
110
+
span: Some(value.span()),
111
111
+
})?
112
112
+
};
88
113
}
89
114
90
115
// Try to match values to expected types
91
116
match (value, expected_type) {
92
117
// Boolean
93
93
-
(Value::Bool { val, .. }, Some(DbusType::Boolean)) =>
94
94
-
Ok(MessageItem::Bool(*val)),
118
118
+
(Value::Bool { val, .. }, Some(DbusType::Boolean)) => Ok(MessageItem::Bool(*val)),
95
119
96
120
// Strings and specialized strings
97
97
-
(Value::String { val, .. }, Some(DbusType::String)) =>
98
98
-
Ok(MessageItem::Str(val.to_owned())),
99
99
-
(Value::String { val, .. }, Some(DbusType::ObjectPath)) =>
100
100
-
Ok(MessageItem::ObjectPath(try_convert!(dbus::strings::Path::new(val)))),
101
101
-
(Value::String { val, .. }, Some(DbusType::Signature)) =>
102
102
-
Ok(MessageItem::Signature(try_convert!(dbus::strings::Signature::new(val)))),
121
121
+
(Value::String { val, .. }, Some(DbusType::String)) => Ok(MessageItem::Str(val.to_owned())),
122
122
+
(Value::String { val, .. }, Some(DbusType::ObjectPath)) => Ok(MessageItem::ObjectPath(
123
123
+
try_convert!(dbus::strings::Path::new(val)),
124
124
+
)),
125
125
+
(Value::String { val, .. }, Some(DbusType::Signature)) => Ok(MessageItem::Signature(
126
126
+
try_convert!(dbus::strings::Signature::new(val)),
127
127
+
)),
103
128
104
129
// Signed ints
105
105
-
(Value::Int { val, .. }, Some(DbusType::Int64)) =>
106
106
-
Ok(MessageItem::Int64(*val)),
107
107
-
(Value::Int { val, .. }, Some(DbusType::Int32)) =>
108
108
-
Ok(MessageItem::Int32(try_convert!(i32::try_from(*val)))),
109
109
-
(Value::Int { val, .. }, Some(DbusType::Int16)) =>
110
110
-
Ok(MessageItem::Int16(try_convert!(i16::try_from(*val)))),
130
130
+
(Value::Int { val, .. }, Some(DbusType::Int64)) => Ok(MessageItem::Int64(*val)),
131
131
+
(Value::Int { val, .. }, Some(DbusType::Int32)) => {
132
132
+
Ok(MessageItem::Int32(try_convert!(i32::try_from(*val))))
133
133
+
}
134
134
+
(Value::Int { val, .. }, Some(DbusType::Int16)) => {
135
135
+
Ok(MessageItem::Int16(try_convert!(i16::try_from(*val))))
136
136
+
}
111
137
112
138
// Unsigned ints
113
113
-
(Value::Int { val, .. }, Some(DbusType::UInt64)) =>
114
114
-
Ok(MessageItem::UInt64(try_convert!(u64::try_from(*val)))),
115
115
-
(Value::Int { val, .. }, Some(DbusType::UInt32)) =>
116
116
-
Ok(MessageItem::UInt32(try_convert!(u32::try_from(*val)))),
117
117
-
(Value::Int { val, .. }, Some(DbusType::UInt16)) =>
118
118
-
Ok(MessageItem::UInt16(try_convert!(u16::try_from(*val)))),
119
119
-
(Value::Int { val, .. }, Some(DbusType::Byte)) =>
120
120
-
Ok(MessageItem::Byte(try_convert!(u8::try_from(*val)))),
139
139
+
(Value::Int { val, .. }, Some(DbusType::UInt64)) => {
140
140
+
Ok(MessageItem::UInt64(try_convert!(u64::try_from(*val))))
141
141
+
}
142
142
+
(Value::Int { val, .. }, Some(DbusType::UInt32)) => {
143
143
+
Ok(MessageItem::UInt32(try_convert!(u32::try_from(*val))))
144
144
+
}
145
145
+
(Value::Int { val, .. }, Some(DbusType::UInt16)) => {
146
146
+
Ok(MessageItem::UInt16(try_convert!(u16::try_from(*val))))
147
147
+
}
148
148
+
(Value::Int { val, .. }, Some(DbusType::Byte)) => {
149
149
+
Ok(MessageItem::Byte(try_convert!(u8::try_from(*val))))
150
150
+
}
121
151
122
152
// Ints from string
123
123
-
(Value::String { val, .. }, Some(DbusType::Int64)) =>
124
124
-
Ok(MessageItem::Int64(try_convert!(i64::from_str(&val[..])))),
125
125
-
(Value::String { val, .. }, Some(DbusType::Int32)) =>
126
126
-
Ok(MessageItem::Int32(try_convert!(i32::from_str(&val[..])))),
127
127
-
(Value::String { val, .. }, Some(DbusType::Int16)) =>
128
128
-
Ok(MessageItem::Int16(try_convert!(i16::from_str(&val[..])))),
129
129
-
(Value::String { val, .. }, Some(DbusType::UInt64)) =>
130
130
-
Ok(MessageItem::UInt64(try_convert!(u64::from_str(&val[..])))),
131
131
-
(Value::String { val, .. }, Some(DbusType::UInt32)) =>
132
132
-
Ok(MessageItem::UInt32(try_convert!(u32::from_str(&val[..])))),
133
133
-
(Value::String { val, .. }, Some(DbusType::UInt16)) =>
134
134
-
Ok(MessageItem::UInt16(try_convert!(u16::from_str(&val[..])))),
135
135
-
(Value::String { val, .. }, Some(DbusType::Byte)) =>
136
136
-
Ok(MessageItem::Byte(try_convert!(u8::from_str(&val[..])))),
153
153
+
(Value::String { val, .. }, Some(DbusType::Int64)) => {
154
154
+
Ok(MessageItem::Int64(try_convert!(i64::from_str(&val[..]))))
155
155
+
}
156
156
+
(Value::String { val, .. }, Some(DbusType::Int32)) => {
157
157
+
Ok(MessageItem::Int32(try_convert!(i32::from_str(&val[..]))))
158
158
+
}
159
159
+
(Value::String { val, .. }, Some(DbusType::Int16)) => {
160
160
+
Ok(MessageItem::Int16(try_convert!(i16::from_str(&val[..]))))
161
161
+
}
162
162
+
(Value::String { val, .. }, Some(DbusType::UInt64)) => {
163
163
+
Ok(MessageItem::UInt64(try_convert!(u64::from_str(&val[..]))))
164
164
+
}
165
165
+
(Value::String { val, .. }, Some(DbusType::UInt32)) => {
166
166
+
Ok(MessageItem::UInt32(try_convert!(u32::from_str(&val[..]))))
167
167
+
}
168
168
+
(Value::String { val, .. }, Some(DbusType::UInt16)) => {
169
169
+
Ok(MessageItem::UInt16(try_convert!(u16::from_str(&val[..]))))
170
170
+
}
171
171
+
(Value::String { val, .. }, Some(DbusType::Byte)) => {
172
172
+
Ok(MessageItem::Byte(try_convert!(u8::from_str(&val[..]))))
173
173
+
}
137
174
138
175
// Float
139
139
-
(Value::Float { val, .. }, Some(DbusType::Double)) =>
140
140
-
Ok(MessageItem::Double(*val)),
141
141
-
(Value::String { val, .. }, Some(DbusType::Double)) =>
142
142
-
Ok(MessageItem::Double(try_convert!(f64::from_str(&val[..])))),
176
176
+
(Value::Float { val, .. }, Some(DbusType::Double)) => Ok(MessageItem::Double(*val)),
177
177
+
(Value::String { val, .. }, Some(DbusType::Double)) => {
178
178
+
Ok(MessageItem::Double(try_convert!(f64::from_str(&val[..]))))
179
179
+
}
143
180
144
181
// Binary
145
182
(Value::Binary { val, .. }, Some(r#type @ DbusType::Array(content_type)))
···
147
184
{
148
185
// FIXME: this is likely pretty inefficient for a bunch of bytes
149
186
let sig = Signature::from(r#type.stringify());
150
150
-
let items = val.iter().cloned().map(MessageItem::Byte).collect::<Vec<_>>();
151
151
-
Ok(MessageItem::Array(MessageItemArray::new(items, sig).unwrap()))
152
152
-
},
187
187
+
let items = val
188
188
+
.iter()
189
189
+
.cloned()
190
190
+
.map(MessageItem::Byte)
191
191
+
.collect::<Vec<_>>();
192
192
+
Ok(MessageItem::Array(
193
193
+
MessageItemArray::new(items, sig).unwrap(),
194
194
+
))
195
195
+
}
153
196
154
197
// List/array
155
198
(Value::List { vals, .. }, Some(r#type @ DbusType::Array(content_type))) => {
156
199
let sig = Signature::from(r#type.stringify());
157
157
-
let items = vals.iter()
200
200
+
let items = vals
201
201
+
.iter()
158
202
.map(|content| to_message_item(content, Some(content_type)))
159
203
.collect::<Result<Vec<MessageItem>, _>>()?;
160
160
-
Ok(MessageItem::Array(MessageItemArray::new(items, sig).unwrap()))
161
161
-
},
204
204
+
Ok(MessageItem::Array(
205
205
+
MessageItemArray::new(items, sig).unwrap(),
206
206
+
))
207
207
+
}
162
208
163
209
// Struct
164
210
(Value::List { vals, .. }, Some(DbusType::Struct(types))) => {
165
211
if vals.len() != types.len() {
166
212
return Err(LabeledError {
167
167
-
label: format!("expected struct with {} element(s) ({:?})", types.len(), types),
213
213
+
label: format!(
214
214
+
"expected struct with {} element(s) ({:?})",
215
215
+
types.len(),
216
216
+
types
217
217
+
),
168
218
msg: format!("this list has {} element(s) instead", vals.len()),
169
169
-
span: Some(value.span())
219
219
+
span: Some(value.span()),
170
220
});
171
221
}
172
172
-
let items = vals.iter().zip(types)
222
222
+
let items = vals
223
223
+
.iter()
224
224
+
.zip(types)
173
225
.map(|(content, r#type)| to_message_item(content, Some(r#type)))
174
226
.collect::<Result<Vec<MessageItem>, _>>()?;
175
227
Ok(MessageItem::Struct(items))
176
176
-
},
228
228
+
}
177
229
178
230
// Record/dict
179
231
(Value::Record { val, .. }, Some(DbusType::Array(content_type)))
···
182
234
if let DbusType::DictEntry(ref key_type, ref val_type) = **content_type {
183
235
let key_sig = Signature::from(key_type.stringify());
184
236
let val_sig = Signature::from(val_type.stringify());
185
185
-
let pairs = val.iter()
237
237
+
let pairs = val
238
238
+
.iter()
186
239
.map(|(key, val)| {
187
240
let key_as_value = Value::string(key, value.span());
188
241
let key_message_item = to_message_item(&key_as_value, Some(key_type))?;
···
190
243
Ok((key_message_item, val_message_item))
191
244
})
192
245
.collect::<Result<Vec<_>, LabeledError>>()?;
193
193
-
Ok(MessageItem::Dict(MessageItemDict::new(pairs, key_sig, val_sig).unwrap()))
246
246
+
Ok(MessageItem::Dict(
247
247
+
MessageItemDict::new(pairs, key_sig, val_sig).unwrap(),
248
248
+
))
194
249
} else {
195
250
unreachable!()
196
251
}
197
197
-
},
252
252
+
}
198
253
199
254
// Variant - use automatic type
200
200
-
(other_value, Some(DbusType::Variant)) =>
201
201
-
Ok(MessageItem::Variant(Box::new(to_message_item(other_value, None)?))),
255
255
+
(other_value, Some(DbusType::Variant)) => Ok(MessageItem::Variant(Box::new(
256
256
+
to_message_item(other_value, None)?,
257
257
+
))),
202
258
203
259
// Value not compatible with expected type
204
204
-
(other_value, Some(expectation)) =>
205
205
-
Err(LabeledError {
206
206
-
label: format!("`{}` can not be converted to the D-Bus `{:?}` type",
207
207
-
other_value.get_type(), expectation),
208
208
-
msg: format!("expected a `{:?}` here", expectation),
209
209
-
span: Some(other_value.span()),
210
210
-
}),
260
260
+
(other_value, Some(expectation)) => Err(LabeledError {
261
261
+
label: format!(
262
262
+
"`{}` can not be converted to the D-Bus `{:?}` type",
263
263
+
other_value.get_type(),
264
264
+
expectation
265
265
+
),
266
266
+
msg: format!("expected a `{:?}` here", expectation),
267
267
+
span: Some(other_value.span()),
268
268
+
}),
211
269
212
270
// Automatic types (with no type expectation)
213
213
-
(Value::String { .. }, None) =>
214
214
-
to_message_item(value, Some(&DbusType::String)),
215
215
-
(Value::Int { .. }, None) =>
216
216
-
to_message_item(value, Some(&DbusType::Int64)),
217
217
-
(Value::Float { .. }, None) =>
218
218
-
to_message_item(value, Some(&DbusType::Double)),
219
219
-
(Value::Bool { .. }, None) =>
220
220
-
to_message_item(value, Some(&DbusType::Boolean)),
221
221
-
(Value::List { .. }, None) =>
222
222
-
to_message_item(value, Some(&DbusType::Array(DbusType::Variant.into()))),
223
223
-
(Value::Record { .. }, None) =>
224
224
-
to_message_item(value, Some(&DbusType::Array(
225
225
-
DbusType::DictEntry(
226
226
-
DbusType::String.into(),
227
227
-
DbusType::Variant.into()
228
228
-
).into()))),
271
271
+
(Value::String { .. }, None) => to_message_item(value, Some(&DbusType::String)),
272
272
+
(Value::Int { .. }, None) => to_message_item(value, Some(&DbusType::Int64)),
273
273
+
(Value::Float { .. }, None) => to_message_item(value, Some(&DbusType::Double)),
274
274
+
(Value::Bool { .. }, None) => to_message_item(value, Some(&DbusType::Boolean)),
275
275
+
(Value::List { .. }, None) => {
276
276
+
to_message_item(value, Some(&DbusType::Array(DbusType::Variant.into())))
277
277
+
}
278
278
+
(Value::Record { .. }, None) => to_message_item(
279
279
+
value,
280
280
+
Some(&DbusType::Array(
281
281
+
DbusType::DictEntry(DbusType::String.into(), DbusType::Variant.into()).into(),
282
282
+
)),
283
283
+
),
229
284
230
285
// No expected type, but can't handle this type
231
231
-
_ =>
232
232
-
Err(LabeledError {
233
233
-
label: format!("can not use values of type `{}` in D-Bus calls", value.get_type()),
234
234
-
msg: "use a supported type here instead".into(),
235
235
-
span: Some(value.span()),
236
236
-
})
286
286
+
_ => Err(LabeledError {
287
287
+
label: format!(
288
288
+
"can not use values of type `{}` in D-Bus calls",
289
289
+
value.get_type()
290
290
+
),
291
291
+
msg: "use a supported type here instead".into(),
292
292
+
span: Some(value.span()),
293
293
+
}),
237
294
}
238
295
}
+72
-60
src/dbus_type.rs
···
48
48
// The next type is the content type of the array
49
49
let (content_type, remainder) = Self::parse(&input[1..])?;
50
50
Ok((Array(content_type.into()), remainder))
51
51
-
},
51
51
+
}
52
52
'(' => {
53
53
// Parse the struct content until we get to the end ) char
54
54
let mut remainder = &input[1..];
···
56
56
loop {
57
57
if remainder.is_empty() {
58
58
break Err("unexpected end of D-Bus type string \
59
59
-
before end of array".into());
60
60
-
} else if remainder.starts_with(')') {
61
61
-
break Ok((DbusType::Struct(types), &remainder[1..]));
59
59
+
before end of array"
60
60
+
.into());
61
61
+
} else if let Some(new_remainder) = remainder.strip_prefix(')') {
62
62
+
break Ok((DbusType::Struct(types), new_remainder));
62
63
} else {
63
64
let (r#type, new_remainder) = Self::parse(remainder)?;
64
65
types.push(r#type);
65
66
remainder = new_remainder;
66
67
}
67
68
}
68
68
-
},
69
69
+
}
69
70
'v' => Ok((Variant, &input[1..])),
70
71
'{' => {
71
72
// Expect two types
72
73
let (key_type, key_remainder) = Self::parse(&input[1..])?;
73
74
let (val_type, val_remainder) = Self::parse(key_remainder)?;
74
75
// Must end with }
75
75
-
if val_remainder.starts_with('}') {
76
76
-
Ok((DbusType::DictEntry(key_type.into(), val_type.into()), &val_remainder[1..]))
76
76
+
if let Some(new_remainder) = val_remainder.strip_prefix('}') {
77
77
+
Ok((
78
78
+
DbusType::DictEntry(key_type.into(), val_type.into()),
79
79
+
new_remainder,
80
80
+
))
77
81
} else {
78
78
-
Err(format!("expected `}}` char to end dictionary in D-Bus type \
79
79
-
but remainder is {:?}", val_remainder))
82
82
+
Err(format!(
83
83
+
"expected `}}` char to end dictionary in D-Bus type \
84
84
+
but remainder is {:?}",
85
85
+
val_remainder
86
86
+
))
80
87
}
81
81
-
},
82
82
-
other => Err(format!("unexpected char {other:?} in D-Bus type representation"))
88
88
+
}
89
89
+
other => Err(format!(
90
90
+
"unexpected char {other:?} in D-Bus type representation"
91
91
+
)),
83
92
}
84
93
}
85
94
···
99
108
use self::DbusType::*;
100
109
101
110
match self {
102
102
-
Byte => 'y'.into(),
103
103
-
Boolean => 'b'.into(),
104
104
-
Int16 => 'n'.into(),
105
105
-
UInt16 => 'q'.into(),
106
106
-
Int32 => 'i'.into(),
107
107
-
UInt32 => 'u'.into(),
108
108
-
Int64 => 'x'.into(),
109
109
-
UInt64 => 't'.into(),
110
110
-
Double => 'd'.into(),
111
111
-
String => 's'.into(),
111
111
+
Byte => 'y'.into(),
112
112
+
Boolean => 'b'.into(),
113
113
+
Int16 => 'n'.into(),
114
114
+
UInt16 => 'q'.into(),
115
115
+
Int32 => 'i'.into(),
116
116
+
UInt32 => 'u'.into(),
117
117
+
Int64 => 'x'.into(),
118
118
+
UInt64 => 't'.into(),
119
119
+
Double => 'd'.into(),
120
120
+
String => 's'.into(),
112
121
ObjectPath => 'o'.into(),
113
113
-
Signature => 'g'.into(),
122
122
+
Signature => 'g'.into(),
114
123
115
124
// a<type>
116
125
Array(content) => format!("a{}", content.stringify()),
···
131
140
132
141
#[cfg(test)]
133
142
macro_rules! should_parse_to {
134
134
-
($str:expr, $result:expr) => (
143
143
+
($str:expr, $result:expr) => {
135
144
assert_eq!(DbusType::parse($str), Ok(($result, "")))
136
136
-
)
145
145
+
};
137
146
}
138
147
139
148
#[test]
···
204
213
use self::DbusType::*;
205
214
should_parse_to!("((xx))", Struct(vec![Struct(vec![Int64, Int64])]));
206
215
should_parse_to!("(y(xx))", Struct(vec![Byte, Struct(vec![Int64, Int64])]));
207
207
-
should_parse_to!("(y(ss)o)", Struct(vec![Byte, Struct(vec![String, String]), ObjectPath]));
216
216
+
should_parse_to!(
217
217
+
"(y(ss)o)",
218
218
+
Struct(vec![Byte, Struct(vec![String, String]), ObjectPath])
219
219
+
);
208
220
should_parse_to!("((yy)s)", Struct(vec![Struct(vec![Byte, Byte]), String]));
209
221
}
210
222
···
224
236
fn test_parse_dict_entry() {
225
237
use self::DbusType::*;
226
238
should_parse_to!("{ss}", DictEntry(String.into(), String.into()));
227
227
-
should_parse_to!("{s(bd)}", DictEntry(String.into(), Struct(vec![Boolean, Double]).into()));
239
239
+
should_parse_to!(
240
240
+
"{s(bd)}",
241
241
+
DictEntry(String.into(), Struct(vec![Boolean, Double]).into())
242
242
+
);
228
243
}
229
244
230
245
#[test]
231
246
fn test_parse_array_dict() {
232
247
use self::DbusType::*;
233
233
-
should_parse_to!("a{sd}", Array(DictEntry(String.into(), Double.into()).into()));
248
248
+
should_parse_to!(
249
249
+
"a{sd}",
250
250
+
Array(DictEntry(String.into(), Double.into()).into())
251
251
+
);
234
252
}
235
253
236
254
#[test]
···
249
267
fn test_parse_all() {
250
268
use self::DbusType::*;
251
269
assert_eq!(DbusType::parse_all(""), Ok(vec![]));
252
252
-
assert_eq!(
253
253
-
DbusType::parse_all("s"),
254
254
-
Ok(vec![
255
255
-
String,
256
256
-
])
257
257
-
);
270
270
+
assert_eq!(DbusType::parse_all("s"), Ok(vec![String,]));
258
271
assert_eq!(
259
272
DbusType::parse_all("isbb"),
260
260
-
Ok(vec![
261
261
-
Int32,
262
262
-
String,
263
263
-
Boolean,
264
264
-
Boolean,
265
265
-
])
273
273
+
Ok(vec![Int32, String, Boolean, Boolean,])
266
274
);
267
275
assert_eq!(
268
276
DbusType::parse_all("ia{s(bi)}s"),
···
276
284
277
285
#[cfg(test)]
278
286
macro_rules! should_stringify_to {
279
279
-
($type:expr, $result:expr) => (
287
287
+
($type:expr, $result:expr) => {
280
288
assert_eq!(DbusType::stringify(&$type), $result)
281
281
-
)
289
289
+
};
282
290
}
283
291
284
292
#[test]
285
293
fn test_stringify_simple_types() {
286
294
use self::DbusType::*;
287
287
-
should_stringify_to!(Byte, "y");
288
288
-
should_stringify_to!(Boolean, "b");
289
289
-
should_stringify_to!(Int16, "n");
290
290
-
should_stringify_to!(UInt16, "q");
291
291
-
should_stringify_to!(Int32, "i");
292
292
-
should_stringify_to!(UInt32, "u");
293
293
-
should_stringify_to!(Int64, "x");
294
294
-
should_stringify_to!(UInt64, "t");
295
295
-
should_stringify_to!(Double, "d");
296
296
-
should_stringify_to!(String, "s");
295
295
+
should_stringify_to!(Byte, "y");
296
296
+
should_stringify_to!(Boolean, "b");
297
297
+
should_stringify_to!(Int16, "n");
298
298
+
should_stringify_to!(UInt16, "q");
299
299
+
should_stringify_to!(Int32, "i");
300
300
+
should_stringify_to!(UInt32, "u");
301
301
+
should_stringify_to!(Int64, "x");
302
302
+
should_stringify_to!(UInt64, "t");
303
303
+
should_stringify_to!(Double, "d");
304
304
+
should_stringify_to!(String, "s");
297
305
should_stringify_to!(ObjectPath, "o");
298
298
-
should_stringify_to!(Signature, "g");
299
299
-
should_stringify_to!(Variant, "v");
306
306
+
should_stringify_to!(Signature, "g");
307
307
+
should_stringify_to!(Variant, "v");
300
308
}
301
309
302
310
#[test]
···
313
321
should_stringify_to!(Struct(vec![Int32]), "(i)");
314
322
should_stringify_to!(Struct(vec![Int32, String]), "(is)");
315
323
should_stringify_to!(Struct(vec![Byte, Int32, String]), "(yis)");
316
316
-
should_stringify_to!(Struct(vec![Byte, Struct(vec![String, Boolean]), String]), "(y(sb)s)");
324
324
+
should_stringify_to!(
325
325
+
Struct(vec![Byte, Struct(vec![String, Boolean]), String]),
326
326
+
"(y(sb)s)"
327
327
+
);
317
328
}
318
329
319
330
#[test]
···
326
337
#[test]
327
338
fn test_stringify_nested() {
328
339
use self::DbusType::*;
329
329
-
should_stringify_to!(Array(DictEntry(String.into(), Int32.into()).into()), "a{si}");
340
340
+
should_stringify_to!(
341
341
+
Array(DictEntry(String.into(), Int32.into()).into()),
342
342
+
"a{si}"
343
343
+
);
330
344
should_stringify_to!(
331
345
Array(
332
346
DictEntry(
333
347
String.into(),
334
334
-
Struct(vec![
335
335
-
Byte,
336
336
-
Array(Int32.into())
337
337
-
]).into()
338
338
-
).into()
348
348
+
Struct(vec![Byte, Array(Int32.into())]).into()
349
349
+
)
350
350
+
.into()
339
351
),
340
352
"a{s(yai)}"
341
353
);
+108
-77
src/introspection.rs
···
1
1
-
use nu_protocol::{Value, record, Span};
1
1
+
use nu_protocol::{record, Span, Value};
2
2
use serde::Deserialize;
3
3
4
4
macro_rules! list_to_value {
5
5
-
($list:expr, $span:expr) => (
5
5
+
($list:expr, $span:expr) => {
6
6
Value::list($list.iter().map(|i| i.to_value($span)).collect(), $span)
7
7
-
)
7
7
+
};
8
8
}
9
9
10
10
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Default)]
···
41
41
/// Find a method on an interface on this node, and then generate the signature of the method
42
42
/// args
43
43
pub fn get_method_args_signature(&self, interface: &str, method: &str) -> Option<String> {
44
44
-
Some(self.get_interface(interface)?.get_method(method)?.in_signature())
44
44
+
Some(
45
45
+
self.get_interface(interface)?
46
46
+
.get_method(method)?
47
47
+
.in_signature(),
48
48
+
)
45
49
}
46
50
47
51
/// Find the signature of a property on an interface on this node
48
52
pub fn get_property_signature(&self, interface: &str, property: &str) -> Option<&str> {
49
49
-
Some(&self.get_interface(interface)?.get_property(property)?.r#type)
53
53
+
Some(
54
54
+
&self
55
55
+
.get_interface(interface)?
56
56
+
.get_property(property)?
57
57
+
.r#type,
58
58
+
)
50
59
}
51
60
52
61
/// Represent the node as a nushell [Value]
53
62
pub fn to_value(&self, span: Span) -> Value {
54
54
-
Value::record(record!{
55
55
-
"name" => self.name.as_ref().map(|s| Value::string(s, span)).unwrap_or_default(),
56
56
-
"interfaces" => list_to_value!(self.interfaces, span),
57
57
-
"children" => list_to_value!(self.children, span),
58
58
-
}, span)
63
63
+
Value::record(
64
64
+
record! {
65
65
+
"name" => self.name.as_ref().map(|s| Value::string(s, span)).unwrap_or_default(),
66
66
+
"interfaces" => list_to_value!(self.interfaces, span),
67
67
+
"children" => list_to_value!(self.children, span),
68
68
+
},
69
69
+
span,
70
70
+
)
59
71
}
60
72
}
61
73
···
89
101
90
102
/// Represent the interface as a nushell [Value]
91
103
pub fn to_value(&self, span: Span) -> Value {
92
92
-
Value::record(record!{
93
93
-
"name" => Value::string(&self.name, span),
94
94
-
"methods" => list_to_value!(self.methods, span),
95
95
-
"signals" => list_to_value!(self.signals, span),
96
96
-
"properties" => list_to_value!(self.properties, span),
97
97
-
"signals" => list_to_value!(self.signals, span),
98
98
-
}, span)
104
104
+
Value::record(
105
105
+
record! {
106
106
+
"name" => Value::string(&self.name, span),
107
107
+
"methods" => list_to_value!(self.methods, span),
108
108
+
"signals" => list_to_value!(self.signals, span),
109
109
+
"properties" => list_to_value!(self.properties, span),
110
110
+
"signals" => list_to_value!(self.signals, span),
111
111
+
},
112
112
+
span,
113
113
+
)
99
114
}
100
115
}
101
116
···
112
127
impl Method {
113
128
/// Get the signature of the method args
114
129
pub fn in_signature(&self) -> String {
115
115
-
self.args.iter()
130
130
+
self.args
131
131
+
.iter()
116
132
.filter(|arg| arg.direction == Direction::In)
117
133
.map(|arg| &arg.r#type[..])
118
134
.collect()
···
121
137
#[allow(dead_code)]
122
138
/// Get the signature of the method result
123
139
pub fn out_signature(&self) -> String {
124
124
-
self.args.iter()
140
140
+
self.args
141
141
+
.iter()
125
142
.filter(|arg| arg.direction == Direction::Out)
126
143
.map(|arg| &arg.r#type[..])
127
144
.collect()
···
129
146
130
147
/// Represent the method as a nushell [Value]
131
148
pub fn to_value(&self, span: Span) -> Value {
132
132
-
Value::record(record!{
133
133
-
"name" => Value::string(&self.name, span),
134
134
-
"args" => list_to_value!(self.args, span),
135
135
-
"annotations" => list_to_value!(self.annotations, span),
136
136
-
}, span)
149
149
+
Value::record(
150
150
+
record! {
151
151
+
"name" => Value::string(&self.name, span),
152
152
+
"args" => list_to_value!(self.args, span),
153
153
+
"annotations" => list_to_value!(self.annotations, span),
154
154
+
},
155
155
+
span,
156
156
+
)
137
157
}
138
158
}
139
159
···
152
172
pub fn new(
153
173
name: impl Into<String>,
154
174
r#type: impl Into<String>,
155
155
-
direction: Direction
175
175
+
direction: Direction,
156
176
) -> MethodArg {
157
177
MethodArg {
158
178
name: Some(name.into()),
···
163
183
164
184
/// Represent the method as a nushell [Value]
165
185
pub fn to_value(&self, span: Span) -> Value {
166
166
-
Value::record(record!{
167
167
-
"name" => self.name.as_ref().map(|n| Value::string(n, span)).unwrap_or_default(),
168
168
-
"type" => Value::string(&self.r#type, span),
169
169
-
"direction" => self.direction.to_value(span),
170
170
-
}, span)
186
186
+
Value::record(
187
187
+
record! {
188
188
+
"name" => self.name.as_ref().map(|n| Value::string(n, span)).unwrap_or_default(),
189
189
+
"type" => Value::string(&self.r#type, span),
190
190
+
"direction" => self.direction.to_value(span),
191
191
+
},
192
192
+
span,
193
193
+
)
171
194
}
172
195
}
173
196
···
181
204
182
205
impl Direction {
183
206
/// Represent the direction as a nushell [Value]
184
184
-
pub fn to_value(&self, span: Span) -> Value {
207
207
+
pub fn to_value(self, span: Span) -> Value {
185
208
match self {
186
209
Direction::In => Value::string("in", span),
187
210
Direction::Out => Value::string("out", span),
···
202
225
impl Signal {
203
226
/// Represent the signal as a nushell [Value]
204
227
pub fn to_value(&self, span: Span) -> Value {
205
205
-
Value::record(record!{
206
206
-
"name" => Value::string(&self.name, span),
207
207
-
"args" => list_to_value!(self.args, span),
208
208
-
"annotations" => list_to_value!(self.annotations, span),
209
209
-
}, span)
228
228
+
Value::record(
229
229
+
record! {
230
230
+
"name" => Value::string(&self.name, span),
231
231
+
"args" => list_to_value!(self.args, span),
232
232
+
"annotations" => list_to_value!(self.annotations, span),
233
233
+
},
234
234
+
span,
235
235
+
)
210
236
}
211
237
}
212
238
···
221
247
impl SignalArg {
222
248
/// Represent the argument as a nushell [Value]
223
249
pub fn to_value(&self, span: Span) -> Value {
224
224
-
Value::record(record!{
225
225
-
"name" => self.name.as_ref().map(|n| Value::string(n, span)).unwrap_or_default(),
226
226
-
"type" => Value::string(&self.r#type, span),
227
227
-
}, span)
250
250
+
Value::record(
251
251
+
record! {
252
252
+
"name" => self.name.as_ref().map(|n| Value::string(n, span)).unwrap_or_default(),
253
253
+
"type" => Value::string(&self.r#type, span),
254
254
+
},
255
255
+
span,
256
256
+
)
228
257
}
229
258
}
230
259
···
241
270
impl Property {
242
271
/// Represent the property as a nushell [Value]
243
272
pub fn to_value(&self, span: Span) -> Value {
244
244
-
Value::record(record!{
245
245
-
"name" => Value::string(&self.name, span),
246
246
-
"type" => Value::string(&self.r#type, span),
247
247
-
"args" => self.access.to_value(span),
248
248
-
"annotations" => list_to_value!(self.annotations, span),
249
249
-
}, span)
273
273
+
Value::record(
274
274
+
record! {
275
275
+
"name" => Value::string(&self.name, span),
276
276
+
"type" => Value::string(&self.r#type, span),
277
277
+
"args" => self.access.to_value(span),
278
278
+
"annotations" => list_to_value!(self.annotations, span),
279
279
+
},
280
280
+
span,
281
281
+
)
250
282
}
251
283
}
252
284
···
279
311
impl Annotation {
280
312
#[cfg(test)]
281
313
pub fn new(name: impl Into<String>, value: impl Into<String>) -> Annotation {
282
282
-
Annotation { name: name.into(), value: value.into() }
314
314
+
Annotation {
315
315
+
name: name.into(),
316
316
+
value: value.into(),
317
317
+
}
283
318
}
284
319
285
320
/// Represent the annotation as a nushell [Value]
286
321
pub fn to_value(&self, span: Span) -> Value {
287
287
-
Value::record(record!{
288
288
-
"name" => Value::string(&self.name, span),
289
289
-
"value" => Value::string(&self.value, span),
290
290
-
}, span)
322
322
+
Value::record(
323
323
+
record! {
324
324
+
"name" => Value::string(&self.name, span),
325
325
+
"value" => Value::string(&self.value, span),
326
326
+
},
327
327
+
span,
328
328
+
)
291
329
}
292
330
}
293
331
···
305
343
MethodArg::new("bar", "as", Direction::In),
306
344
MethodArg::new("baz", "a{us}", Direction::Out),
307
345
],
308
308
-
annotations: vec![
309
309
-
Annotation::new("org.freedesktop.DBus.Deprecated", "true"),
310
310
-
],
346
346
+
annotations: vec![Annotation::new("org.freedesktop.DBus.Deprecated", "true")],
311
347
},
312
348
Method {
313
349
name: "Bazify".into(),
···
320
356
},
321
357
Method {
322
358
name: "Mogrify".into(),
323
323
-
args: vec![
324
324
-
MethodArg::new("bar", "(iiav)", Direction::In),
325
325
-
],
326
326
-
annotations: vec![]
327
327
-
},
328
328
-
],
329
329
-
signals: vec![
330
330
-
Signal {
331
331
-
name: "Changed".into(),
332
332
-
args: vec![
333
333
-
SignalArg { name: Some("new_value".into()), r#type: "b".into() },
334
334
-
],
335
335
-
annotations: vec![]
336
336
-
},
337
337
-
],
338
338
-
properties: vec![
339
339
-
Property {
340
340
-
name: "Bar".into(),
341
341
-
r#type: "y".into(),
342
342
-
access: Access::ReadWrite,
359
359
+
args: vec![MethodArg::new("bar", "(iiav)", Direction::In)],
343
360
annotations: vec![],
344
344
-
}
361
361
+
},
345
362
],
346
346
-
annotations: vec![]
363
363
+
signals: vec![Signal {
364
364
+
name: "Changed".into(),
365
365
+
args: vec![SignalArg {
366
366
+
name: Some("new_value".into()),
367
367
+
r#type: "b".into(),
368
368
+
}],
369
369
+
annotations: vec![],
370
370
+
}],
371
371
+
properties: vec![Property {
372
372
+
name: "Bar".into(),
373
373
+
r#type: "y".into(),
374
374
+
access: Access::ReadWrite,
375
375
+
annotations: vec![],
376
376
+
}],
377
377
+
annotations: vec![],
347
378
}],
348
379
children: vec![
349
380
Node::with_name("child_of_sample_object"),
350
381
Node::with_name("another_child_of_sample_object"),
351
351
-
]
382
382
+
],
352
383
}
353
384
}
354
385
+53
-31
src/main.rs
···
1
1
-
use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin, EvaluatedCall, LabeledError};
2
2
-
use nu_protocol::{PluginSignature, Value, SyntaxShape, PluginExample, Span, Type};
1
1
+
use nu_plugin::{serve_plugin, EvaluatedCall, LabeledError, MsgPackSerializer, Plugin};
2
2
+
use nu_protocol::{PluginExample, PluginSignature, Span, SyntaxShape, Type, Value};
3
3
4
4
+
mod client;
4
5
mod config;
5
5
-
mod client;
6
6
mod convert;
7
7
mod dbus_type;
8
8
mod introspection;
9
9
mod pattern;
10
10
11
11
-
use config::*;
12
11
use client::*;
12
12
+
use config::*;
13
13
14
14
use crate::pattern::Pattern;
15
15
···
23
23
impl Plugin for NuPluginDbus {
24
24
fn signature(&self) -> Vec<PluginSignature> {
25
25
macro_rules! str {
26
26
-
($s:expr) => (Value::string($s, Span::unknown()))
26
26
+
($s:expr) => {
27
27
+
Value::string($s, Span::unknown())
28
28
+
};
27
29
}
28
30
vec![
29
31
PluginSignature::build("dbus")
30
30
-
.is_dbus_command()
32
32
+
.dbus_command()
31
33
.usage("Commands for interacting with D-Bus"),
32
34
PluginSignature::build("dbus introspect")
33
33
-
.is_dbus_command()
35
35
+
.dbus_command()
34
36
.accepts_dbus_client_options()
35
37
.accepts_timeout()
36
38
.usage("Introspect a D-Bus object")
···
65
67
},
66
68
]),
67
69
PluginSignature::build("dbus call")
68
68
-
.is_dbus_command()
70
70
+
.dbus_command()
69
71
.accepts_dbus_client_options()
70
72
.accepts_timeout()
71
73
.usage("Call a method and get its response")
···
108
110
},
109
111
]),
110
112
PluginSignature::build("dbus get")
111
111
-
.is_dbus_command()
113
113
+
.dbus_command()
112
114
.accepts_dbus_client_options()
113
115
.accepts_timeout()
114
116
.usage("Get a D-Bus property")
···
139
141
},
140
142
]),
141
143
PluginSignature::build("dbus get-all")
142
142
-
.is_dbus_command()
144
144
+
.dbus_command()
143
145
.accepts_dbus_client_options()
144
146
.accepts_timeout()
145
147
.usage("Get all D-Bus properties for the given object")
···
165
167
},
166
168
]),
167
169
PluginSignature::build("dbus set")
168
168
-
.is_dbus_command()
170
170
+
.dbus_command()
169
171
.accepts_dbus_client_options()
170
172
.accepts_timeout()
171
173
.usage("Set a D-Bus property")
···
196
198
},
197
199
]),
198
200
PluginSignature::build("dbus list")
199
199
-
.is_dbus_command()
201
201
+
.dbus_command()
200
202
.accepts_dbus_client_options()
201
203
.accepts_timeout()
202
204
.usage("List all available connection names on the bus")
···
244
246
"dbus" => Err(LabeledError {
245
247
label: "The `dbus` command requires a subcommand".into(),
246
248
msg: "add --help to see subcommands".into(),
247
247
-
span: Some(call.head)
249
249
+
span: Some(call.head),
248
250
}),
249
251
250
252
"dbus introspect" => self.introspect(call),
···
257
259
_ => Err(LabeledError {
258
260
label: "Plugin invoked with unknown command name".into(),
259
261
msg: "unknown command".into(),
260
260
-
span: Some(call.head)
261
261
-
})
262
262
+
span: Some(call.head),
263
263
+
}),
262
264
}
263
265
}
264
266
}
265
267
266
268
/// For conveniently adding the base options to a dbus command
267
269
trait DbusSignatureUtilExt {
268
268
-
fn is_dbus_command(self) -> Self;
270
270
+
fn dbus_command(self) -> Self;
269
271
fn accepts_dbus_client_options(self) -> Self;
270
272
fn accepts_timeout(self) -> Self;
271
273
}
272
274
273
275
impl DbusSignatureUtilExt for PluginSignature {
274
274
-
fn is_dbus_command(self) -> Self {
276
276
+
fn dbus_command(self) -> Self {
275
277
self.search_terms(vec!["dbus".into()])
276
278
.category(nu_protocol::Category::Platform)
277
279
}
···
279
281
fn accepts_dbus_client_options(self) -> Self {
280
282
self.switch("session", "Send to the session message bus (default)", None)
281
283
.switch("system", "Send to the system message bus", None)
282
282
-
.switch("started", "Send to the bus that started this process, if applicable", None)
283
283
-
.named("bus", SyntaxShape::String, "Send to the bus server at the given address", None)
284
284
-
.named("peer", SyntaxShape::String,
284
284
+
.switch(
285
285
+
"started",
286
286
+
"Send to the bus that started this process, if applicable",
287
287
+
None,
288
288
+
)
289
289
+
.named(
290
290
+
"bus",
291
291
+
SyntaxShape::String,
292
292
+
"Send to the bus server at the given address",
293
293
+
None,
294
294
+
)
295
295
+
.named(
296
296
+
"peer",
297
297
+
SyntaxShape::String,
285
298
"Send to a non-bus D-Bus server at the given address. \
286
299
Will not call the Hello method on initialization.",
287
287
-
None)
300
300
+
None,
301
301
+
)
288
302
}
289
303
290
304
fn accepts_timeout(self) -> Self {
291
291
-
self.named("timeout", SyntaxShape::Duration, "How long to wait for a response", None)
305
305
+
self.named(
306
306
+
"timeout",
307
307
+
SyntaxShape::Duration,
308
308
+
"How long to wait for a response",
309
309
+
None,
310
310
+
)
292
311
}
293
312
}
294
313
···
296
315
fn introspect(&self, call: &EvaluatedCall) -> Result<Value, LabeledError> {
297
316
let config = DbusClientConfig::try_from(call)?;
298
317
let dbus = DbusClient::new(config)?;
299
299
-
let node = dbus.introspect(
300
300
-
&call.get_flag("dest")?.unwrap(),
301
301
-
&call.req(0)?,
302
302
-
)?;
318
318
+
let node = dbus.introspect(&call.get_flag("dest")?.unwrap(), &call.req(0)?)?;
303
319
Ok(node.to_value(call.head))
304
320
}
305
321
···
312
328
&call.req(1)?,
313
329
&call.req(2)?,
314
330
call.get_flag("signature")?.as_ref(),
315
315
-
&call.positional[3..]
331
331
+
&call.positional[3..],
316
332
)?;
317
333
318
334
let flatten = !call.get_flag::<bool>("no-flatten")?.unwrap_or(false);
···
322
338
match values.len() {
323
339
0 if flatten => Ok(Value::nothing(call.head)),
324
340
1 if flatten => Ok(values.into_iter().nth(0).unwrap()),
325
325
-
_ => Ok(Value::list(values, call.head))
341
341
+
_ => Ok(Value::list(values, call.head)),
326
342
}
327
343
}
328
344
···
364
380
fn list(&self, call: &EvaluatedCall) -> Result<Value, LabeledError> {
365
381
let config = DbusClientConfig::try_from(call)?;
366
382
let dbus = DbusClient::new(config)?;
367
367
-
let pattern = call.opt::<String>(0)?.map(|pat| Pattern::new(&pat, Some('.')));
383
383
+
let pattern = call
384
384
+
.opt::<String>(0)?
385
385
+
.map(|pat| Pattern::new(&pat, Some('.')));
368
386
let result = dbus.list(pattern.as_ref())?;
369
387
Ok(Value::list(
370
370
-
result.into_iter().map(|s| Value::string(s, call.head)).collect(),
371
371
-
call.head))
388
388
+
result
389
389
+
.into_iter()
390
390
+
.map(|s| Value::string(s, call.head))
391
391
+
.collect(),
392
392
+
call.head,
393
393
+
))
372
394
}
373
395
}
+208
-125
src/pattern.rs
···
17
17
let mut tokens = vec![];
18
18
for ch in pattern.chars() {
19
19
match ch {
20
20
-
'*' =>
20
20
+
'*' => {
21
21
if tokens.last() == Some(&PatternToken::OneWildcard) {
22
22
*tokens.last_mut().unwrap() = PatternToken::ManyWildcard;
23
23
} else {
24
24
tokens.push(PatternToken::OneWildcard);
25
25
-
},
26
26
-
'?' =>
27
27
-
tokens.push(PatternToken::AnyChar),
28
28
-
_ =>
29
29
-
match tokens.last_mut() {
30
30
-
Some(PatternToken::Exact(ref mut s)) => s.push(ch),
31
31
-
_ => tokens.push(PatternToken::Exact(ch.into())),
32
32
-
},
25
25
+
}
26
26
+
}
27
27
+
'?' => tokens.push(PatternToken::AnyChar),
28
28
+
_ => match tokens.last_mut() {
29
29
+
Some(PatternToken::Exact(ref mut s)) => s.push(ch),
30
30
+
_ => tokens.push(PatternToken::Exact(ch.into())),
31
31
+
},
33
32
}
34
33
}
35
34
Pattern { separator, tokens }
···
57
56
MatchState::Precise => {
58
57
// Can't possibly match
59
58
return false;
60
60
-
},
59
59
+
}
61
60
MatchState::ScanAhead { stop_at_separator } => {
62
61
if search_str.is_empty() {
63
62
// End of input, can't match
64
63
return false;
65
64
}
66
66
-
if stop_at_separator &&
67
67
-
self.separator.is_some_and(|sep| search_str.starts_with(sep)) {
65
65
+
if stop_at_separator
66
66
+
&& self
67
67
+
.separator
68
68
+
.is_some_and(|sep| search_str.starts_with(sep))
69
69
+
{
68
70
// Found the separator. Consume a char and revert to precise
69
71
// mode
70
72
search_str = &search_str[1..];
···
76
78
}
77
79
}
78
80
}
79
79
-
},
81
81
+
}
80
82
PatternToken::OneWildcard => {
81
83
// Set the mode to ScanAhead, stopping at separator
82
82
-
state = MatchState::ScanAhead { stop_at_separator: true };
84
84
+
state = MatchState::ScanAhead {
85
85
+
stop_at_separator: true,
86
86
+
};
83
87
tokens = &tokens[1..];
84
84
-
},
88
88
+
}
85
89
PatternToken::ManyWildcard => {
86
90
// Set the mode to ScanAhead, ignoring separator
87
87
-
state = MatchState::ScanAhead { stop_at_separator: false };
91
91
+
state = MatchState::ScanAhead {
92
92
+
stop_at_separator: false,
93
93
+
};
88
94
tokens = &tokens[1..];
89
89
-
},
95
95
+
}
90
96
PatternToken::AnyChar => {
91
97
if !search_str.is_empty() {
92
98
// Take a char from the search str and continue
···
96
102
// End of input
97
103
return false;
98
104
}
99
99
-
},
105
105
+
}
100
106
}
101
107
}
102
102
-
#[cfg(test)] {
103
103
-
println!("end, state={:?}, search_str={:?}, tokens={:?}", state, search_str, tokens);
108
108
+
#[cfg(test)]
109
109
+
{
110
110
+
println!(
111
111
+
"end, state={:?}, search_str={:?}, tokens={:?}",
112
112
+
state, search_str, tokens
113
113
+
);
104
114
}
105
115
if !search_str.is_empty() {
106
116
// If the search str is not empty at the end
···
108
118
// We didn't end with a wildcard, so this is a fail
109
119
MatchState::Precise => false,
110
120
// This could be a match as long as the separator isn't contained in the remainder
111
111
-
MatchState::ScanAhead { stop_at_separator: true } =>
121
121
+
MatchState::ScanAhead {
122
122
+
stop_at_separator: true,
123
123
+
} => {
112
124
if let Some(separator) = self.separator {
113
125
!search_str.contains(separator)
114
126
} else {
115
127
// No separator specified, so this is a success
116
128
true
117
117
-
},
129
129
+
}
130
130
+
}
118
131
// Always a success, no matter what remains
119
119
-
MatchState::ScanAhead { stop_at_separator: false } => true,
132
132
+
MatchState::ScanAhead {
133
133
+
stop_at_separator: false,
134
134
+
} => true,
120
135
}
121
136
} else {
122
137
// The match has succeeded - there is nothing more to match
···
129
144
fn test_pattern_new() {
130
145
assert_eq!(
131
146
Pattern::new("", Some('/')),
132
132
-
Pattern { separator: Some('/'), tokens: vec![] }
147
147
+
Pattern {
148
148
+
separator: Some('/'),
149
149
+
tokens: vec![]
150
150
+
}
133
151
);
134
152
assert_eq!(
135
153
Pattern::new("", None),
136
136
-
Pattern { separator: None, tokens: vec![] }
154
154
+
Pattern {
155
155
+
separator: None,
156
156
+
tokens: vec![]
157
157
+
}
137
158
);
138
159
assert_eq!(
139
160
Pattern::new("org.freedesktop.DBus", Some('.')),
140
140
-
Pattern { separator: Some('.'), tokens: vec![
141
141
-
PatternToken::Exact("org.freedesktop.DBus".into()),
142
142
-
] }
161
161
+
Pattern {
162
162
+
separator: Some('.'),
163
163
+
tokens: vec![PatternToken::Exact("org.freedesktop.DBus".into()),]
164
164
+
}
143
165
);
144
166
assert_eq!(
145
167
Pattern::new("*", Some('.')),
146
146
-
Pattern { separator: Some('.'), tokens: vec![
147
147
-
PatternToken::OneWildcard,
148
148
-
] }
168
168
+
Pattern {
169
169
+
separator: Some('.'),
170
170
+
tokens: vec![PatternToken::OneWildcard,]
171
171
+
}
149
172
);
150
173
assert_eq!(
151
174
Pattern::new("**", Some('.')),
152
152
-
Pattern { separator: Some('.'), tokens: vec![
153
153
-
PatternToken::ManyWildcard,
154
154
-
] }
175
175
+
Pattern {
176
176
+
separator: Some('.'),
177
177
+
tokens: vec![PatternToken::ManyWildcard,]
178
178
+
}
155
179
);
156
180
assert_eq!(
157
181
Pattern::new("?", Some('.')),
158
158
-
Pattern { separator: Some('.'), tokens: vec![
159
159
-
PatternToken::AnyChar,
160
160
-
] }
182
182
+
Pattern {
183
183
+
separator: Some('.'),
184
184
+
tokens: vec![PatternToken::AnyChar,]
185
185
+
}
161
186
);
162
187
assert_eq!(
163
188
Pattern::new("org.freedesktop.*", Some('.')),
164
164
-
Pattern { separator: Some('.'), tokens: vec![
165
165
-
PatternToken::Exact("org.freedesktop.".into()),
166
166
-
PatternToken::OneWildcard,
167
167
-
] }
189
189
+
Pattern {
190
190
+
separator: Some('.'),
191
191
+
tokens: vec![
192
192
+
PatternToken::Exact("org.freedesktop.".into()),
193
193
+
PatternToken::OneWildcard,
194
194
+
]
195
195
+
}
168
196
);
169
197
assert_eq!(
170
198
Pattern::new("org.freedesktop.**", Some('.')),
171
171
-
Pattern { separator: Some('.'), tokens: vec![
172
172
-
PatternToken::Exact("org.freedesktop.".into()),
173
173
-
PatternToken::ManyWildcard,
174
174
-
] }
199
199
+
Pattern {
200
200
+
separator: Some('.'),
201
201
+
tokens: vec![
202
202
+
PatternToken::Exact("org.freedesktop.".into()),
203
203
+
PatternToken::ManyWildcard,
204
204
+
]
205
205
+
}
175
206
);
176
207
assert_eq!(
177
208
Pattern::new("org.*.DBus", Some('.')),
178
178
-
Pattern { separator: Some('.'), tokens: vec![
179
179
-
PatternToken::Exact("org.".into()),
180
180
-
PatternToken::OneWildcard,
181
181
-
PatternToken::Exact(".DBus".into()),
182
182
-
] }
209
209
+
Pattern {
210
210
+
separator: Some('.'),
211
211
+
tokens: vec![
212
212
+
PatternToken::Exact("org.".into()),
213
213
+
PatternToken::OneWildcard,
214
214
+
PatternToken::Exact(".DBus".into()),
215
215
+
]
216
216
+
}
183
217
);
184
218
assert_eq!(
185
219
Pattern::new("org.**.DBus", Some('.')),
186
186
-
Pattern { separator: Some('.'), tokens: vec![
187
187
-
PatternToken::Exact("org.".into()),
188
188
-
PatternToken::ManyWildcard,
189
189
-
PatternToken::Exact(".DBus".into()),
190
190
-
] }
220
220
+
Pattern {
221
221
+
separator: Some('.'),
222
222
+
tokens: vec![
223
223
+
PatternToken::Exact("org.".into()),
224
224
+
PatternToken::ManyWildcard,
225
225
+
PatternToken::Exact(".DBus".into()),
226
226
+
]
227
227
+
}
191
228
);
192
229
assert_eq!(
193
230
Pattern::new("org.**.?Bus", Some('.')),
194
194
-
Pattern { separator: Some('.'), tokens: vec![
195
195
-
PatternToken::Exact("org.".into()),
196
196
-
PatternToken::ManyWildcard,
197
197
-
PatternToken::Exact(".".into()),
198
198
-
PatternToken::AnyChar,
199
199
-
PatternToken::Exact("Bus".into()),
200
200
-
] }
231
231
+
Pattern {
232
232
+
separator: Some('.'),
233
233
+
tokens: vec![
234
234
+
PatternToken::Exact("org.".into()),
235
235
+
PatternToken::ManyWildcard,
236
236
+
PatternToken::Exact(".".into()),
237
237
+
PatternToken::AnyChar,
238
238
+
PatternToken::Exact("Bus".into()),
239
239
+
]
240
240
+
}
201
241
);
202
242
assert_eq!(
203
243
Pattern::new("org.free*top", Some('.')),
204
204
-
Pattern { separator: Some('.'), tokens: vec![
205
205
-
PatternToken::Exact("org.free".into()),
206
206
-
PatternToken::OneWildcard,
207
207
-
PatternToken::Exact("top".into()),
208
208
-
] }
244
244
+
Pattern {
245
245
+
separator: Some('.'),
246
246
+
tokens: vec![
247
247
+
PatternToken::Exact("org.free".into()),
248
248
+
PatternToken::OneWildcard,
249
249
+
PatternToken::Exact("top".into()),
250
250
+
]
251
251
+
}
209
252
);
210
253
assert_eq!(
211
254
Pattern::new("org.free**top", Some('.')),
212
212
-
Pattern { separator: Some('.'), tokens: vec![
213
213
-
PatternToken::Exact("org.free".into()),
214
214
-
PatternToken::ManyWildcard,
215
215
-
PatternToken::Exact("top".into()),
216
216
-
] }
255
255
+
Pattern {
256
256
+
separator: Some('.'),
257
257
+
tokens: vec![
258
258
+
PatternToken::Exact("org.free".into()),
259
259
+
PatternToken::ManyWildcard,
260
260
+
PatternToken::Exact("top".into()),
261
261
+
]
262
262
+
}
217
263
);
218
264
assert_eq!(
219
265
Pattern::new("org.**top", Some('.')),
220
220
-
Pattern { separator: Some('.'), tokens: vec![
221
221
-
PatternToken::Exact("org.".into()),
222
222
-
PatternToken::ManyWildcard,
223
223
-
PatternToken::Exact("top".into()),
224
224
-
] }
266
266
+
Pattern {
267
267
+
separator: Some('.'),
268
268
+
tokens: vec![
269
269
+
PatternToken::Exact("org.".into()),
270
270
+
PatternToken::ManyWildcard,
271
271
+
PatternToken::Exact("top".into()),
272
272
+
]
273
273
+
}
225
274
);
226
275
assert_eq!(
227
276
Pattern::new("**top", Some('.')),
228
228
-
Pattern { separator: Some('.'), tokens: vec![
229
229
-
PatternToken::ManyWildcard,
230
230
-
PatternToken::Exact("top".into()),
231
231
-
] }
277
277
+
Pattern {
278
278
+
separator: Some('.'),
279
279
+
tokens: vec![
280
280
+
PatternToken::ManyWildcard,
281
281
+
PatternToken::Exact("top".into()),
282
282
+
]
283
283
+
}
232
284
);
233
285
assert_eq!(
234
286
Pattern::new("org.free**", Some('.')),
235
235
-
Pattern { separator: Some('.'), tokens: vec![
236
236
-
PatternToken::Exact("org.free".into()),
237
237
-
PatternToken::ManyWildcard,
238
238
-
] }
287
287
+
Pattern {
288
288
+
separator: Some('.'),
289
289
+
tokens: vec![
290
290
+
PatternToken::Exact("org.free".into()),
291
291
+
PatternToken::ManyWildcard,
292
292
+
]
293
293
+
}
239
294
);
240
295
}
241
296
242
297
#[test]
243
298
fn test_pattern_is_match_empty() {
244
244
-
let pat = Pattern { separator: Some('.'), tokens: vec![] };
299
299
+
let pat = Pattern {
300
300
+
separator: Some('.'),
301
301
+
tokens: vec![],
302
302
+
};
245
303
assert!(pat.is_match(""));
246
304
assert!(!pat.is_match("anystring"));
247
305
assert!(!pat.is_match("anystring.anyotherstring"));
···
249
307
250
308
#[test]
251
309
fn test_pattern_is_match_exact() {
252
252
-
let pat = Pattern { separator: Some('.'), tokens: vec![
253
253
-
PatternToken::Exact("specific".into()),
254
254
-
] };
310
310
+
let pat = Pattern {
311
311
+
separator: Some('.'),
312
312
+
tokens: vec![PatternToken::Exact("specific".into())],
313
313
+
};
255
314
assert!(pat.is_match("specific"));
256
315
assert!(!pat.is_match(""));
257
316
assert!(!pat.is_match("specifi"));
···
260
319
261
320
#[test]
262
321
fn test_pattern_is_match_one_wildcard() {
263
263
-
let pat = Pattern { separator: Some('.'), tokens: vec![
264
264
-
PatternToken::Exact("foo.".into()),
265
265
-
PatternToken::OneWildcard,
266
266
-
PatternToken::Exact(".baz".into()),
267
267
-
] };
322
322
+
let pat = Pattern {
323
323
+
separator: Some('.'),
324
324
+
tokens: vec![
325
325
+
PatternToken::Exact("foo.".into()),
326
326
+
PatternToken::OneWildcard,
327
327
+
PatternToken::Exact(".baz".into()),
328
328
+
],
329
329
+
};
268
330
assert!(pat.is_match("foo.bar.baz"));
269
331
assert!(pat.is_match("foo.grok.baz"));
270
332
assert!(pat.is_match("foo..baz"));
···
277
339
278
340
#[test]
279
341
fn test_pattern_is_match_one_wildcard_at_end() {
280
280
-
let pat = Pattern { separator: Some('.'), tokens: vec![
281
281
-
PatternToken::Exact("foo.".into()),
282
282
-
PatternToken::OneWildcard,
283
283
-
] };
342
342
+
let pat = Pattern {
343
343
+
separator: Some('.'),
344
344
+
tokens: vec![
345
345
+
PatternToken::Exact("foo.".into()),
346
346
+
PatternToken::OneWildcard,
347
347
+
],
348
348
+
};
284
349
assert!(pat.is_match("foo.bar"));
285
350
assert!(pat.is_match("foo.grok"));
286
351
assert!(pat.is_match("foo."));
···
292
357
293
358
#[test]
294
359
fn test_pattern_is_match_one_wildcard_at_start() {
295
295
-
let pat = Pattern { separator: Some('.'), tokens: vec![
296
296
-
PatternToken::OneWildcard,
297
297
-
PatternToken::Exact(".bar".into()),
298
298
-
] };
360
360
+
let pat = Pattern {
361
361
+
separator: Some('.'),
362
362
+
tokens: vec![
363
363
+
PatternToken::OneWildcard,
364
364
+
PatternToken::Exact(".bar".into()),
365
365
+
],
366
366
+
};
299
367
assert!(pat.is_match("foo.bar"));
300
368
assert!(pat.is_match("grok.bar"));
301
369
assert!(pat.is_match(".bar"));
···
307
375
308
376
#[test]
309
377
fn test_pattern_is_match_one_wildcard_no_separator() {
310
310
-
let pat = Pattern { separator: None, tokens: vec![
311
311
-
PatternToken::Exact("foo.".into()),
312
312
-
PatternToken::OneWildcard,
313
313
-
PatternToken::Exact(".baz".into()),
314
314
-
] };
378
378
+
let pat = Pattern {
379
379
+
separator: None,
380
380
+
tokens: vec![
381
381
+
PatternToken::Exact("foo.".into()),
382
382
+
PatternToken::OneWildcard,
383
383
+
PatternToken::Exact(".baz".into()),
384
384
+
],
385
385
+
};
315
386
assert!(pat.is_match("foo.bar.baz"));
316
387
assert!(pat.is_match("foo.grok.baz"));
317
388
assert!(pat.is_match("foo..baz"));
···
325
396
326
397
#[test]
327
398
fn test_pattern_is_match_many_wildcard() {
328
328
-
let pat = Pattern { separator: Some('.'), tokens: vec![
329
329
-
PatternToken::Exact("foo.".into()),
330
330
-
PatternToken::ManyWildcard,
331
331
-
PatternToken::Exact(".baz".into()),
332
332
-
] };
399
399
+
let pat = Pattern {
400
400
+
separator: Some('.'),
401
401
+
tokens: vec![
402
402
+
PatternToken::Exact("foo.".into()),
403
403
+
PatternToken::ManyWildcard,
404
404
+
PatternToken::Exact(".baz".into()),
405
405
+
],
406
406
+
};
333
407
assert!(pat.is_match("foo.bar.baz"));
334
408
assert!(pat.is_match("foo.grok.baz"));
335
409
assert!(pat.is_match("foo..baz"));
···
343
417
344
418
#[test]
345
419
fn test_pattern_is_match_many_wildcard_at_end() {
346
346
-
let pat = Pattern { separator: Some('.'), tokens: vec![
347
347
-
PatternToken::Exact("foo.".into()),
348
348
-
PatternToken::ManyWildcard,
349
349
-
] };
420
420
+
let pat = Pattern {
421
421
+
separator: Some('.'),
422
422
+
tokens: vec![
423
423
+
PatternToken::Exact("foo.".into()),
424
424
+
PatternToken::ManyWildcard,
425
425
+
],
426
426
+
};
350
427
assert!(pat.is_match("foo.bar"));
351
428
assert!(pat.is_match("foo.grok"));
352
429
assert!(pat.is_match("foo."));
···
358
435
359
436
#[test]
360
437
fn test_pattern_is_match_many_wildcard_at_start() {
361
361
-
let pat = Pattern { separator: Some('.'), tokens: vec![
362
362
-
PatternToken::ManyWildcard,
363
363
-
PatternToken::Exact(".bar".into()),
364
364
-
] };
438
438
+
let pat = Pattern {
439
439
+
separator: Some('.'),
440
440
+
tokens: vec![
441
441
+
PatternToken::ManyWildcard,
442
442
+
PatternToken::Exact(".bar".into()),
443
443
+
],
444
444
+
};
365
445
assert!(pat.is_match("foo.bar"));
366
446
assert!(pat.is_match("grok.bar"));
367
447
assert!(pat.is_match("should.match.bar"));
···
373
453
374
454
#[test]
375
455
fn test_pattern_is_match_any_char() {
376
376
-
let pat = Pattern { separator: Some('.'), tokens: vec![
377
377
-
PatternToken::Exact("fo".into()),
378
378
-
PatternToken::AnyChar,
379
379
-
PatternToken::Exact(".baz".into()),
380
380
-
] };
456
456
+
let pat = Pattern {
457
457
+
separator: Some('.'),
458
458
+
tokens: vec![
459
459
+
PatternToken::Exact("fo".into()),
460
460
+
PatternToken::AnyChar,
461
461
+
PatternToken::Exact(".baz".into()),
462
462
+
],
463
463
+
};
381
464
assert!(pat.is_match("foo.baz"));
382
465
assert!(pat.is_match("foe.baz"));
383
466
assert!(pat.is_match("foi.baz"));