2
2
3
3
use glob:: glob;
4
4
use rustc_serialize:: { Decodable , Decoder } ;
5
- use std:: collections:: { BTreeSet } ;
5
+ use std:: collections:: { BTreeSet , HashMap } ;
6
6
use std:: fs:: { self , File } ;
7
7
use std:: io;
8
8
use std:: io:: prelude:: * ;
@@ -175,13 +175,28 @@ impl GpioConfig {
175
175
GpioConfig :: from_str ( & contents[ ..] )
176
176
}
177
177
178
- /// Merge this config with other yielding a new, merged version
178
+ /// Merge other into self (takes ownership of other)
179
179
///
180
180
/// If in conflict, the other GPIO config takes priority.
181
181
pub fn update ( & mut self , other : GpioConfig ) {
182
- // TODO: This needs to actually resolve conflicts rather than
183
- // blindly writing over as it does now.
184
- self . pins . extend ( other. pins )
182
+ for other_pin in other. pins {
183
+ // determine the case we are dealing with
184
+ let existing = match self . pins . iter_mut ( ) . find ( |p| p. num == other_pin. num ) {
185
+ Some ( pin) => {
186
+ pin. names . extend ( other_pin. names . clone ( ) ) ;
187
+ pin. direction = other_pin. direction . clone ( ) ; // TODO impl copy
188
+ pin. export = other_pin. export ;
189
+ pin. active_low = other_pin. active_low ;
190
+ true
191
+ } ,
192
+ None => false ,
193
+ } ;
194
+
195
+ if !existing {
196
+ self . pins . push ( other_pin) ;
197
+ }
198
+
199
+ }
185
200
}
186
201
}
187
202
@@ -192,12 +207,9 @@ mod test {
192
207
use std:: collections:: BTreeSet ;
193
208
use sysfs_gpio:: Direction as D ;
194
209
195
- #[ test]
196
- fn test_parse_basic ( ) {
197
- let configstr = r#"
210
+ static BASIC_CFG : & ' static str = r#"
198
211
# Basic Form
199
212
[[pins]]
200
-
201
213
num = 73
202
214
names = ["reset_button"]
203
215
direction = "in" # default: in
@@ -209,12 +221,54 @@ num = 37
209
221
names = ["status_led", "A27", "green_led"]
210
222
direction = "out"
211
223
"# ;
212
- let config = GpioConfig :: from_str ( configstr) . unwrap ( ) ;
224
+
225
+ static COMPACT_CFG : & ' static str = r#"
226
+ pins = [
227
+ { num = 73, names = ["reset_button"], direction = "in", active_low = true, export = true},
228
+ { num = 37, names = ["status_led", "A27", "green_led"], direction = "out"},
229
+ ]
230
+ "# ;
231
+
232
+ static MISSING_PINNUM_CFG : & ' static str = r#"
233
+ [[pins]]
234
+ export = true
235
+ "# ;
236
+
237
+ static PARTIALLY_OVERLAPS_BASIC_CFG : & ' static str = r#"
238
+ # Add a new alias to pin 73
239
+ [[pins]]
240
+ num = 73
241
+ names = ["new_name"]
242
+
243
+
244
+ # Change pin 37 to be an input (not output)
245
+ [[pins]]
246
+ num = 37
247
+ direction = "in"
248
+
249
+ # New pin 88
250
+ [[pins]]
251
+ num = 88
252
+ names = ["wildcard"]
253
+ "# ;
254
+
255
+ #[ test]
256
+ fn test_parse_basic ( ) {
257
+ let config = GpioConfig :: from_str ( BASIC_CFG ) . unwrap ( ) ;
213
258
let status_led = config. pins . get ( 1 ) . unwrap ( ) ;
214
259
let names = BTreeSet :: from_iter (
215
260
vec ! ( String :: from( "status_led" ) ,
216
261
String :: from( "A27" ) ,
217
262
String :: from( "green_led" ) ) ) ;
263
+
264
+ let reset_button = config. pins . get ( 0 ) . unwrap ( ) ;
265
+ assert_eq ! ( reset_button. num, 73 ) ;
266
+ assert_eq ! ( reset_button. names,
267
+ BTreeSet :: from_iter( vec!( String :: from( "reset_button" ) ) ) ) ;
268
+ assert_eq ! ( reset_button. direction, D :: In ) ;
269
+ assert_eq ! ( reset_button. active_low, true ) ;
270
+ assert_eq ! ( reset_button. export, true ) ;
271
+
218
272
assert_eq ! ( status_led. names, names) ;
219
273
assert_eq ! ( status_led. direction, D :: Out ) ;
220
274
assert_eq ! ( status_led. active_low, false ) ;
@@ -223,13 +277,7 @@ direction = "out"
223
277
224
278
#[ test]
225
279
fn test_parser_compact ( ) {
226
- let configstr = r#"
227
- pins = [
228
- { num = 73, names = ["reset_button"], direction = "in", active_low = true, export = true},
229
- { num = 37, names = ["status_led", "A27", "green_led"], direction = "out"},
230
- ]
231
- "# ;
232
- let config = GpioConfig :: from_str ( configstr) . unwrap ( ) ;
280
+ let config = GpioConfig :: from_str ( COMPACT_CFG ) . unwrap ( ) ;
233
281
let status_led = config. pins . get ( 1 ) . unwrap ( ) ;
234
282
let names = BTreeSet :: from_iter (
235
283
vec ! ( String :: from( "status_led" ) ,
@@ -252,11 +300,7 @@ pins = [
252
300
253
301
#[ test]
254
302
fn test_parser_missing_pinnum ( ) {
255
- let configstr = r#"
256
- [[pins]]
257
- export = true
258
- "# ;
259
- match GpioConfig :: from_str ( configstr) {
303
+ match GpioConfig :: from_str ( MISSING_PINNUM_CFG ) {
260
304
Err ( Error :: DecodingError ( _) ) => { } ,
261
305
_ => panic ! ( "Expected a decoding error" ) ,
262
306
}
@@ -265,12 +309,42 @@ export = true
265
309
#[ test]
266
310
fn test_parse_error_bad_toml ( ) {
267
311
// basically, just garbage data
268
- let configstr = r#"
269
- [] -*-..asdf=-=-@#$%^&*()
270
- "# ;
312
+ let configstr = r"[] -*-..asdf=-=-@#$%^&*()" ;
271
313
match GpioConfig :: from_str ( configstr) {
272
314
Err ( Error :: ParserErrors ( e) ) => { } ,
273
315
_ => panic ! ( "Did not receive parse error when expected" ) ,
274
316
}
275
317
}
318
+
319
+ #[ test]
320
+ fn test_merge_configs ( ) {
321
+ let mut config = GpioConfig :: from_str ( BASIC_CFG ) . unwrap ( ) ;
322
+ let cfg2 = GpioConfig :: from_str ( PARTIALLY_OVERLAPS_BASIC_CFG ) . unwrap ( ) ;
323
+
324
+ // perform the merge
325
+ config. update ( cfg2) ;
326
+
327
+ let reset_button = config. pins . get ( 0 ) . unwrap ( ) ;
328
+ assert_eq ! ( reset_button. num, 73 ) ;
329
+ assert_eq ! ( reset_button. names, BTreeSet :: from_iter(
330
+ vec!( String :: from( "reset_button" ) ,
331
+ String :: from( "new_name" ) ) ) ) ;
332
+ assert_eq ! ( reset_button. direction, D :: In ) ;
333
+ assert_eq ! ( reset_button. active_low, false ) ;
334
+ assert_eq ! ( reset_button. export, true ) ;
335
+
336
+ let status_led = config. pins . get ( 1 ) . unwrap ( ) ;
337
+ let names = BTreeSet :: from_iter (
338
+ vec ! ( String :: from( "status_led" ) ,
339
+ String :: from( "A27" ) ,
340
+ String :: from( "green_led" ) ) ) ;
341
+ assert_eq ! ( status_led. names, names) ;
342
+ assert_eq ! ( status_led. direction, D :: In ) ;
343
+ assert_eq ! ( status_led. active_low, false ) ;
344
+ assert_eq ! ( status_led. export, true ) ;
345
+
346
+ let wildcard = config. pins . get ( 2 ) . unwrap ( ) ;
347
+ assert_eq ! ( wildcard. num, 88 ) ;
348
+ assert_eq ! ( wildcard. names, BTreeSet :: from_iter( vec!( String :: from( "wildcard" ) ) ) ) ;
349
+ }
276
350
}
0 commit comments