1use crate::bytecode_constants::*;
6use crate::compiler::Symbol;
7use crate::compiler::symbol_table::get_deprecated_key_identifier_str;
8use crate::interpreter::common::*;
9use crate::interpreter::decode_bind_rules::DecodedBindRules;
10use crate::parser::bind_library;
11use core::hash::{Hash, Hasher};
12use num_traits::FromPrimitive;
13use std::borrow::Borrow;
14use std::cmp::Ordering;
15use std::collections::HashMap;
16
17#[derive(PartialEq)]
18enum Condition {
19 Unconditional,
20 Equal,
21 Inequal,
22}
23
24enum RawSymbol<'a> {
25 NumberValue(u64),
26 Key(&'a str),
27 StringValue(&'a str),
28 BoolValue(bool),
29 EnumValue(&'a str),
30}
31
32#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
36pub enum PropertyKey {
37 NumberKey(u64),
38 StringKey(String),
39}
40
41#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
42pub enum PropertyKeyRef<'a> {
43 NumberKey(u64),
44 StringKey(&'a str),
45}
46
47pub trait PropertyKeyLookup {
48 fn as_key_ref(&self) -> PropertyKeyRef<'_>;
49}
50
51impl PropertyKeyLookup for PropertyKey {
52 fn as_key_ref(&self) -> PropertyKeyRef<'_> {
53 match self {
54 PropertyKey::NumberKey(k) => PropertyKeyRef::NumberKey(*k),
55 PropertyKey::StringKey(k) => PropertyKeyRef::StringKey(k.as_str()),
56 }
57 }
58}
59
60impl PropertyKeyLookup for PropertyKeyRef<'_> {
61 fn as_key_ref(&self) -> PropertyKeyRef<'_> {
62 *self
63 }
64}
65
66impl Hash for PropertyKey {
67 fn hash<H: Hasher>(&self, state: &mut H) {
68 self.as_key_ref().hash(state);
69 }
70}
71
72impl Hash for dyn PropertyKeyLookup + '_ {
73 fn hash<H: Hasher>(&self, state: &mut H) {
74 self.as_key_ref().hash(state);
75 }
76}
77
78impl PartialEq for dyn PropertyKeyLookup + '_ {
79 fn eq(&self, other: &Self) -> bool {
80 self.as_key_ref() == other.as_key_ref()
81 }
82}
83
84impl Eq for dyn PropertyKeyLookup + '_ {}
85
86impl PartialOrd for dyn PropertyKeyLookup + '_ {
87 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
88 Some(self.cmp(other))
89 }
90}
91
92impl Ord for dyn PropertyKeyLookup + '_ {
93 fn cmp(&self, other: &Self) -> Ordering {
94 self.as_key_ref().cmp(&other.as_key_ref())
95 }
96}
97
98impl<'a> Borrow<dyn PropertyKeyLookup + 'a> for PropertyKey {
99 fn borrow(&self) -> &(dyn PropertyKeyLookup + 'a) {
100 self
101 }
102}
103
104pub type DeviceProperties = HashMap<PropertyKey, Symbol>;
105
106pub struct MatchBindData<'a> {
107 pub symbol_table: &'a HashMap<u32, String>,
108 pub instructions: &'a Vec<u8>,
109}
110
111struct DeviceMatcher<'a> {
112 properties: &'a DeviceProperties,
113 symbol_table: &'a HashMap<u32, String>,
114 iter: BytecodeIter<'a>,
115}
116
117impl<'a> DeviceMatcher<'a> {
118 pub fn match_bind(mut self) -> Result<bool, BytecodeError> {
119 while let Some(byte) = self.iter.next() {
120 let op_byte = FromPrimitive::from_u8(*byte).ok_or(BytecodeError::InvalidOp(*byte))?;
121 match op_byte {
122 RawOp::EqualCondition | RawOp::InequalCondition => {
123 if !self.evaluate_condition_inst(op_byte)? {
124 return Ok(false);
125 }
126 }
127 RawOp::Abort => {
128 return Ok(false);
129 }
130 RawOp::UnconditionalJump => self.evaluate_jump_inst(Condition::Unconditional)?,
131 RawOp::JumpIfEqual => self.evaluate_jump_inst(Condition::Equal)?,
132 RawOp::JumpIfNotEqual => self.evaluate_jump_inst(Condition::Inequal)?,
133 RawOp::JumpLandPad => {
134 }
136 };
137 }
138
139 Ok(true)
140 }
141
142 fn evaluate_condition_inst(&mut self, op: RawOp) -> Result<bool, BytecodeError> {
144 let condition = match op {
145 RawOp::EqualCondition => Condition::Equal,
146 RawOp::InequalCondition => Condition::Inequal,
147 _ => panic!(
148 "evaluate_condition_inst() should only be called for Equal or Inequal instructions"
149 ),
150 };
151
152 Ok(self.read_and_evaluate_values(condition)?)
153 }
154
155 fn evaluate_jump_inst(&mut self, condition: Condition) -> Result<(), BytecodeError> {
156 let offset = next_u32(&mut self.iter)?;
157 if condition != Condition::Unconditional && !self.read_and_evaluate_values(condition)? {
158 return Ok(());
159 }
160
161 for _ in 0..offset {
163 next_u8(&mut self.iter)?;
164 }
165
166 if *next_u8(&mut self.iter)? != RawOp::JumpLandPad as u8 {
168 return Err(BytecodeError::InvalidJumpLocation);
169 }
170
171 Ok(())
172 }
173
174 fn read_and_evaluate_values(&mut self, condition: Condition) -> Result<bool, BytecodeError> {
176 let property_key = match self.read_next_value()? {
177 RawSymbol::NumberValue(key) => PropertyKeyRef::NumberKey(key),
178 RawSymbol::StringValue(key) | RawSymbol::Key(key) => PropertyKeyRef::StringKey(key),
179 RawSymbol::BoolValue(_) | RawSymbol::EnumValue(_) => {
180 return Err(BytecodeError::InvalidKeyType);
181 }
182 };
183
184 let expected_value = self.read_next_value()?;
185 let mut node_property_value = self.properties.get(&property_key as &dyn PropertyKeyLookup);
186
187 if node_property_value.is_none()
191 && let PropertyKeyRef::NumberKey(int_key) = property_key
192 && let Some(str_key) = get_deprecated_key_identifier_str(int_key as u32)
193 {
194 node_property_value =
195 self.properties.get(&PropertyKeyRef::StringKey(str_key) as &dyn PropertyKeyLookup);
196 }
197
198 match node_property_value {
199 None => Ok(condition == Condition::Inequal),
200 Some(value) => compare_symbols(condition, &expected_value, value),
201 }
202 }
203
204 fn read_next_value(&mut self) -> Result<RawSymbol<'a>, BytecodeError> {
207 let value_type = *next_u8(&mut self.iter)?;
208 let value_type = FromPrimitive::from_u8(value_type)
209 .ok_or(BytecodeError::InvalidValueType(value_type))?;
210
211 let value = next_u32(&mut self.iter)?;
212 match value_type {
213 RawValueType::NumberValue => Ok(RawSymbol::NumberValue(value as u64)),
214 RawValueType::Key => Ok(RawSymbol::Key(self.lookup_symbol_table(value)?)),
215 RawValueType::StringValue => {
216 Ok(RawSymbol::StringValue(self.lookup_symbol_table(value)?))
217 }
218 RawValueType::BoolValue => match value {
219 0x0 => Ok(RawSymbol::BoolValue(false)),
220 0x1 => Ok(RawSymbol::BoolValue(true)),
221 _ => Err(BytecodeError::InvalidBoolValue(value)),
222 },
223 RawValueType::EnumValue => Ok(RawSymbol::EnumValue(self.lookup_symbol_table(value)?)),
224 }
225 }
226
227 fn lookup_symbol_table(&self, key: u32) -> Result<&'a str, BytecodeError> {
228 self.symbol_table
229 .get(&key)
230 .map(String::as_str)
231 .ok_or(BytecodeError::MissingEntryInSymbolTable(key))
232 }
233}
234
235fn compare_symbols(
236 condition: Condition,
237 lhs: &RawSymbol<'_>,
238 rhs: &Symbol,
239) -> Result<bool, BytecodeError> {
240 let is_equal = match (lhs, rhs) {
244 (RawSymbol::NumberValue(a), Symbol::NumberValue(b)) => a == b,
245 (RawSymbol::BoolValue(a), Symbol::BoolValue(b)) => a == b,
246 (
247 RawSymbol::StringValue(a) | RawSymbol::EnumValue(a),
248 Symbol::StringValue(b) | Symbol::EnumValue(b),
249 ) => *a == b.as_str(),
250 (RawSymbol::Key(a), Symbol::Key(b, vt)) => {
251 *a == b.as_str() && *vt == bind_library::ValueType::Str
252 }
253 _ => return Err(BytecodeError::MismatchValueTypes),
254 };
255
256 Ok(match condition {
257 Condition::Equal => is_equal,
258 Condition::Inequal => !is_equal,
259 Condition::Unconditional => {
260 panic!("This function shouldn't be called for Unconditional.")
261 }
262 })
263}
264
265pub fn match_bytecode(
268 bytecode: Vec<u8>,
269 properties: &DeviceProperties,
270) -> Result<bool, BytecodeError> {
271 let decoded_bind_rules = DecodedBindRules::from_bytecode(bytecode)?;
272 let matcher = DeviceMatcher {
273 properties: &properties,
274 symbol_table: &decoded_bind_rules.symbol_table,
275 iter: decoded_bind_rules.instructions.iter(),
276 };
277 matcher.match_bind()
278}
279
280pub fn match_bind(
282 bind_data: MatchBindData,
283 properties: &DeviceProperties,
284) -> Result<bool, BytecodeError> {
285 let matcher = DeviceMatcher {
286 properties: &properties,
287 symbol_table: &bind_data.symbol_table,
288 iter: bind_data.instructions.iter(),
289 };
290 matcher.match_bind()
291}
292
293#[cfg(test)]
294mod test {
295 use super::*;
296
297 const OP_BYTES: u32 = 1;
299 const VALUE_BYTES: u32 = 5;
300 const OFFSET_BYTES: u32 = 4;
301
302 const ABORT_BYTES: u32 = OP_BYTES;
304 const COND_INST_BYTES: u32 = OP_BYTES + VALUE_BYTES + VALUE_BYTES;
305 const UNCOND_JMP_BYTES: u32 = OP_BYTES + OFFSET_BYTES;
306 const COND_JMP_BYTES: u32 = OP_BYTES + OFFSET_BYTES + VALUE_BYTES + VALUE_BYTES;
307 const JMP_PAD_BYTES: u32 = OP_BYTES;
308
309 struct EncodedValue {
310 value_type: RawValueType,
311 value: u32,
312 }
313
314 fn append_encoded_value(bytecode: &mut Vec<u8>, encoded_val: EncodedValue) {
315 bytecode.push(encoded_val.value_type as u8);
316 bytecode.extend_from_slice(&encoded_val.value.to_le_bytes());
317 }
318
319 fn append_abort(bytecode: &mut Vec<u8>) {
320 bytecode.push(0x30);
321 }
322
323 fn append_equal_cond(
324 bytecode: &mut Vec<u8>,
325 property_key: EncodedValue,
326 property_value: EncodedValue,
327 ) {
328 bytecode.push(0x01);
329 append_encoded_value(bytecode, property_key);
330 append_encoded_value(bytecode, property_value);
331 }
332
333 fn append_inequal_cond(
334 bytecode: &mut Vec<u8>,
335 property_key: EncodedValue,
336 property_value: EncodedValue,
337 ) {
338 bytecode.push(0x02);
339 append_encoded_value(bytecode, property_key);
340 append_encoded_value(bytecode, property_value);
341 }
342
343 fn append_unconditional_jump(bytecode: &mut Vec<u8>, offset: u32) {
344 bytecode.push(0x10);
345 bytecode.extend_from_slice(&offset.to_le_bytes());
346 }
347
348 fn append_jump_if_equal(
349 bytecode: &mut Vec<u8>,
350 offset: u32,
351 property_key: EncodedValue,
352 property_value: EncodedValue,
353 ) {
354 bytecode.push(0x11);
355 bytecode.extend_from_slice(&offset.to_le_bytes());
356 append_encoded_value(bytecode, property_key);
357 append_encoded_value(bytecode, property_value);
358 }
359
360 fn append_jump_if_not_equal(
361 bytecode: &mut Vec<u8>,
362 offset: u32,
363 property_key: EncodedValue,
364 property_value: EncodedValue,
365 ) {
366 bytecode.push(0x12);
367 bytecode.extend_from_slice(&offset.to_le_bytes());
368 append_encoded_value(bytecode, property_key);
369 append_encoded_value(bytecode, property_value);
370 }
371
372 fn append_jump_pad(bytecode: &mut Vec<u8>) {
373 bytecode.push(0x20);
374 }
375
376 fn verify_match_result(
377 expected_result: Result<bool, BytecodeError>,
378 bind_rules: DecodedBindRules,
379 device_properties: &DeviceProperties,
380 ) {
381 let matcher = DeviceMatcher {
382 properties: device_properties,
383 symbol_table: &bind_rules.symbol_table,
384 iter: bind_rules.instructions.iter(),
385 };
386
387 assert_eq!(expected_result, matcher.match_bind());
388 }
389
390 #[test]
391 fn empty_instructions() {
392 verify_match_result(
393 Ok(true),
394 DecodedBindRules {
395 symbol_table: HashMap::new(),
396 instructions: vec![],
397 decoded_instructions: vec![],
398 debug_info: None,
399 },
400 &HashMap::new(),
401 );
402 }
403
404 #[test]
405 fn equal_condition_with_number_property_keys() {
406 let mut device_properties: DeviceProperties = HashMap::new();
407 device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
408 device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
409
410 let mut instructions: Vec<u8> = vec![];
412 append_equal_cond(
413 &mut instructions,
414 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
415 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
416 );
417 verify_match_result(
418 Ok(true),
419 DecodedBindRules {
420 symbol_table: HashMap::new(),
421 instructions: instructions,
422 decoded_instructions: vec![],
423 debug_info: None,
424 },
425 &device_properties,
426 );
427
428 let mut instructions: Vec<u8> = vec![];
430 append_equal_cond(
431 &mut instructions,
432 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
433 EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
434 );
435 verify_match_result(
436 Ok(false),
437 DecodedBindRules {
438 symbol_table: HashMap::new(),
439 instructions: instructions,
440 decoded_instructions: vec![],
441 debug_info: None,
442 },
443 &device_properties,
444 );
445
446 let mut instructions: Vec<u8> = vec![];
448 append_equal_cond(
449 &mut instructions,
450 EncodedValue { value_type: RawValueType::NumberValue, value: 3 },
451 EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
452 );
453 verify_match_result(
454 Ok(false),
455 DecodedBindRules {
456 symbol_table: HashMap::new(),
457 instructions: instructions,
458 decoded_instructions: vec![],
459 debug_info: None,
460 },
461 &device_properties,
462 );
463 }
464
465 #[test]
466 fn equal_condition_with_string_property_keys() {
467 let mut device_properties: DeviceProperties = HashMap::new();
468 device_properties.insert(
469 PropertyKey::StringKey("nightjar".to_string()),
470 Symbol::StringValue("poorwill".to_string()),
471 );
472
473 device_properties.insert(
474 PropertyKey::StringKey("poorwill".to_string()),
475 Symbol::EnumValue("nighthawk".to_string()),
476 );
477
478 let mut symbol_table: HashMap<u32, String> = HashMap::new();
479 symbol_table.insert(1, "nightjar".to_string());
480 symbol_table.insert(2, "poorwill".to_string());
481 symbol_table.insert(3, "nighthawk".to_string());
482
483 let mut instructions: Vec<u8> = vec![];
485 append_equal_cond(
486 &mut instructions,
487 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
488 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
489 );
490 append_equal_cond(
491 &mut instructions,
492 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
493 EncodedValue { value_type: RawValueType::EnumValue, value: 3 },
494 );
495 verify_match_result(
496 Ok(true),
497 DecodedBindRules {
498 symbol_table: symbol_table.clone(),
499 instructions: instructions,
500 decoded_instructions: vec![],
501 debug_info: None,
502 },
503 &device_properties,
504 );
505
506 let mut instructions: Vec<u8> = vec![];
508 append_equal_cond(
509 &mut instructions,
510 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
511 EncodedValue { value_type: RawValueType::StringValue, value: 3 },
512 );
513 verify_match_result(
514 Ok(false),
515 DecodedBindRules {
516 symbol_table: symbol_table.clone(),
517 instructions: instructions,
518 decoded_instructions: vec![],
519 debug_info: None,
520 },
521 &device_properties,
522 );
523
524 let mut instructions: Vec<u8> = vec![];
526 append_equal_cond(
527 &mut instructions,
528 EncodedValue { value_type: RawValueType::StringValue, value: 3 },
529 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
530 );
531 verify_match_result(
532 Ok(false),
533 DecodedBindRules {
534 symbol_table: symbol_table.clone(),
535 instructions: instructions,
536 decoded_instructions: vec![],
537 debug_info: None,
538 },
539 &device_properties,
540 );
541 }
542
543 #[test]
544 fn inequal_condition_with_number_property_keys() {
545 let mut device_properties: DeviceProperties = HashMap::new();
546 device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
547 device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
548
549 let mut instructions: Vec<u8> = vec![];
551 append_inequal_cond(
552 &mut instructions,
553 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
554 EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
555 );
556 verify_match_result(
557 Ok(true),
558 DecodedBindRules {
559 symbol_table: HashMap::new(),
560 instructions: instructions,
561 decoded_instructions: vec![],
562 debug_info: None,
563 },
564 &device_properties,
565 );
566
567 let mut instructions: Vec<u8> = vec![];
569 append_inequal_cond(
570 &mut instructions,
571 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
572 EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
573 );
574 verify_match_result(
575 Ok(true),
576 DecodedBindRules {
577 symbol_table: HashMap::new(),
578 instructions: instructions,
579 decoded_instructions: vec![],
580 debug_info: None,
581 },
582 &device_properties,
583 );
584
585 let mut instructions: Vec<u8> = vec![];
587 append_inequal_cond(
588 &mut instructions,
589 EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
590 EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
591 );
592 verify_match_result(
593 Ok(false),
594 DecodedBindRules {
595 symbol_table: HashMap::new(),
596 instructions: instructions,
597 decoded_instructions: vec![],
598 debug_info: None,
599 },
600 &device_properties,
601 );
602 }
603
604 #[test]
605 fn inequal_condition_with_string_property_keys() {
606 let mut device_properties: DeviceProperties = HashMap::new();
607 device_properties.insert(
608 PropertyKey::StringKey("nightjar".to_string()),
609 Symbol::StringValue("poorwill".to_string()),
610 );
611
612 let mut symbol_table: HashMap<u32, String> = HashMap::new();
613 symbol_table.insert(1, "nightjar".to_string());
614 symbol_table.insert(2, "poorwill".to_string());
615
616 let mut instructions: Vec<u8> = vec![];
618 append_inequal_cond(
619 &mut instructions,
620 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
621 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
622 );
623 verify_match_result(
624 Ok(true),
625 DecodedBindRules {
626 symbol_table: symbol_table.clone(),
627 instructions: instructions,
628 decoded_instructions: vec![],
629 debug_info: None,
630 },
631 &device_properties,
632 );
633
634 let mut instructions: Vec<u8> = vec![];
637 append_inequal_cond(
638 &mut instructions,
639 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
640 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
641 );
642 verify_match_result(
643 Ok(true),
644 DecodedBindRules {
645 symbol_table: symbol_table.clone(),
646 instructions: instructions,
647 decoded_instructions: vec![],
648 debug_info: None,
649 },
650 &device_properties,
651 );
652
653 let mut instructions: Vec<u8> = vec![];
655 append_inequal_cond(
656 &mut instructions,
657 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
658 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
659 );
660 verify_match_result(
661 Ok(false),
662 DecodedBindRules {
663 symbol_table: symbol_table.clone(),
664 instructions: instructions,
665 decoded_instructions: vec![],
666 debug_info: None,
667 },
668 &device_properties,
669 );
670 }
671
672 #[test]
673 fn unconditional_abort() {
674 let mut instructions: Vec<u8> = vec![];
675 append_abort(&mut instructions);
676 verify_match_result(
677 Ok(false),
678 DecodedBindRules {
679 symbol_table: HashMap::new(),
680 instructions: instructions,
681 decoded_instructions: vec![],
682 debug_info: None,
683 },
684 &HashMap::new(),
685 );
686 }
687
688 #[test]
689 fn match_with_key_values() {
690 let mut device_properties: DeviceProperties = HashMap::new();
691 device_properties
692 .insert(PropertyKey::StringKey("timberdoodle".to_string()), Symbol::NumberValue(2000));
693
694 let mut symbol_table: HashMap<u32, String> = HashMap::new();
695 symbol_table.insert(1, "timberdoodle".to_string());
696
697 let mut instructions: Vec<u8> = vec![];
698 append_equal_cond(
699 &mut instructions,
700 EncodedValue { value_type: RawValueType::Key, value: 1 },
701 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
702 );
703 verify_match_result(
704 Ok(true),
705 DecodedBindRules {
706 symbol_table: symbol_table.clone(),
707 instructions: instructions,
708 decoded_instructions: vec![],
709 debug_info: None,
710 },
711 &device_properties,
712 );
713
714 let mut instructions: Vec<u8> = vec![];
715 append_equal_cond(
716 &mut instructions,
717 EncodedValue { value_type: RawValueType::Key, value: 1 },
718 EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
719 );
720 verify_match_result(
721 Ok(false),
722 DecodedBindRules {
723 symbol_table: symbol_table,
724 instructions: instructions,
725 decoded_instructions: vec![],
726 debug_info: None,
727 },
728 &device_properties,
729 );
730 }
731
732 #[test]
733 fn match_with_bool_values() {
734 let mut device_properties: DeviceProperties = HashMap::new();
735 device_properties.insert(PropertyKey::NumberKey(1), Symbol::BoolValue(true));
736
737 let mut instructions: Vec<u8> = vec![];
738 append_equal_cond(
739 &mut instructions,
740 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
741 EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
742 );
743 verify_match_result(
744 Ok(true),
745 DecodedBindRules {
746 symbol_table: HashMap::new(),
747 instructions: instructions,
748 decoded_instructions: vec![],
749 debug_info: None,
750 },
751 &device_properties,
752 );
753
754 let mut instructions: Vec<u8> = vec![];
755 append_equal_cond(
756 &mut instructions,
757 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
758 EncodedValue { value_type: RawValueType::BoolValue, value: 0 },
759 );
760 verify_match_result(
761 Ok(false),
762 DecodedBindRules {
763 symbol_table: HashMap::new(),
764 instructions: instructions,
765 decoded_instructions: vec![],
766 debug_info: None,
767 },
768 &device_properties,
769 );
770 }
771
772 #[test]
773 fn match_with_str_deprecated_keys() {
774 let mut device_properties: DeviceProperties = HashMap::new();
775 device_properties.insert(
776 PropertyKey::StringKey("fuchsia.BIND_PROTOCOL".to_string()),
777 Symbol::NumberValue(10),
778 );
779 device_properties.insert(
780 PropertyKey::StringKey("fuchsia.BIND_AUTOBIND".to_string()),
781 Symbol::NumberValue(5),
782 );
783
784 let mut instructions: Vec<u8> = vec![];
785 append_equal_cond(
786 &mut instructions,
787 EncodedValue {
788 value_type: RawValueType::NumberValue,
789 value: 0x01, },
791 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
792 );
793 append_equal_cond(
794 &mut instructions,
795 EncodedValue {
796 value_type: RawValueType::NumberValue,
797 value: 0x02, },
799 EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
800 );
801 verify_match_result(
802 Ok(true),
803 DecodedBindRules {
804 symbol_table: HashMap::new(),
805 instructions: instructions,
806 decoded_instructions: vec![],
807 debug_info: None,
808 },
809 &device_properties,
810 );
811 }
812
813 #[test]
814 fn missing_entry_in_symbol_table() {
815 let mut symbol_table: HashMap<u32, String> = HashMap::new();
816 symbol_table.insert(1, "nightjar".to_string());
817 symbol_table.insert(2, "poorwill".to_string());
818
819 let mut instructions: Vec<u8> = vec![];
820 append_inequal_cond(
821 &mut instructions,
822 EncodedValue { value_type: RawValueType::StringValue, value: 10 },
823 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
824 );
825 verify_match_result(
826 Err(BytecodeError::MissingEntryInSymbolTable(10)),
827 DecodedBindRules {
828 symbol_table: HashMap::new(),
829 instructions: instructions,
830 decoded_instructions: vec![],
831 debug_info: None,
832 },
833 &HashMap::new(),
834 );
835
836 let mut instructions: Vec<u8> = vec![];
837 append_inequal_cond(
838 &mut instructions,
839 EncodedValue { value_type: RawValueType::Key, value: 15 },
840 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
841 );
842 verify_match_result(
843 Err(BytecodeError::MissingEntryInSymbolTable(15)),
844 DecodedBindRules {
845 symbol_table: HashMap::new(),
846 instructions: instructions,
847 decoded_instructions: vec![],
848 debug_info: None,
849 },
850 &HashMap::new(),
851 );
852 }
853
854 #[test]
855 fn invalid_op() {
856 let mut instructions: Vec<u8> = vec![0xFF];
857 append_inequal_cond(
858 &mut instructions,
859 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
860 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
861 );
862
863 verify_match_result(
864 Err(BytecodeError::InvalidOp(0xFF)),
865 DecodedBindRules {
866 symbol_table: HashMap::new(),
867 instructions: instructions,
868 decoded_instructions: vec![],
869 debug_info: None,
870 },
871 &HashMap::new(),
872 );
873 }
874
875 #[test]
876 fn invalid_value_type() {
877 let instructions: Vec<u8> = vec![0x01, 0x05, 0, 0, 0, 0, 0x01, 0, 0, 0, 0];
878 verify_match_result(
879 Err(BytecodeError::InvalidValueType(0x05)),
880 DecodedBindRules {
881 symbol_table: HashMap::new(),
882 instructions: instructions,
883 decoded_instructions: vec![],
884 debug_info: None,
885 },
886 &HashMap::new(),
887 );
888 }
889
890 #[test]
891 fn invalid_bool_value() {
892 let mut instructions: Vec<u8> = vec![];
893 append_inequal_cond(
894 &mut instructions,
895 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
896 EncodedValue { value_type: RawValueType::BoolValue, value: 15 },
897 );
898
899 verify_match_result(
900 Err(BytecodeError::InvalidBoolValue(15)),
901 DecodedBindRules {
902 symbol_table: HashMap::new(),
903 instructions: instructions,
904 decoded_instructions: vec![],
905 debug_info: None,
906 },
907 &HashMap::new(),
908 );
909 }
910
911 #[test]
912 fn invalid_key_type() {
913 let mut instructions: Vec<u8> = vec![];
914 append_inequal_cond(
915 &mut instructions,
916 EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
917 EncodedValue { value_type: RawValueType::BoolValue, value: 15 },
918 );
919
920 verify_match_result(
921 Err(BytecodeError::InvalidKeyType),
922 DecodedBindRules {
923 symbol_table: HashMap::new(),
924 instructions: instructions,
925 decoded_instructions: vec![],
926 debug_info: None,
927 },
928 &HashMap::new(),
929 );
930 }
931
932 #[test]
933 fn mismatch_value_types() {
934 let mut device_properties: DeviceProperties = HashMap::new();
935 device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
936 device_properties.insert(
937 PropertyKey::StringKey("tyrant".to_string()),
938 Symbol::StringValue("flycatcher".to_string()),
939 );
940
941 let mut symbol_table: HashMap<u32, String> = HashMap::new();
942 symbol_table.insert(1, "tyrant".to_string());
943 symbol_table.insert(2, "flycatcher".to_string());
944
945 let mut instructions: Vec<u8> = vec![];
946 append_equal_cond(
947 &mut instructions,
948 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
949 EncodedValue { value_type: RawValueType::NumberValue, value: 15 },
950 );
951
952 verify_match_result(
953 Err(BytecodeError::MismatchValueTypes),
954 DecodedBindRules {
955 symbol_table: symbol_table,
956 instructions: instructions,
957 decoded_instructions: vec![],
958 debug_info: None,
959 },
960 &device_properties,
961 );
962 }
963
964 #[test]
965 fn invalid_condition_statement() {
966 let instructions: Vec<u8> = vec![0x01, 0x02, 0, 0, 0];
967 verify_match_result(
968 Err(BytecodeError::UnexpectedEnd),
969 DecodedBindRules {
970 symbol_table: HashMap::new(),
971 instructions: instructions,
972 decoded_instructions: vec![],
973 debug_info: None,
974 },
975 &HashMap::new(),
976 );
977 }
978
979 #[test]
980 fn match_with_multiple_condition_statements() {
981 let mut device_properties: DeviceProperties = HashMap::new();
982 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
983 device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
984 device_properties.insert(
985 PropertyKey::StringKey("rail".to_string()),
986 Symbol::StringValue("crake".to_string()),
987 );
988
989 let mut symbol_table: HashMap<u32, String> = HashMap::new();
990 symbol_table.insert(1, "crake".to_string());
991 symbol_table.insert(2, "rail".to_string());
992
993 let mut instructions: Vec<u8> = vec![];
994 append_inequal_cond(
995 &mut instructions,
996 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
997 EncodedValue { value_type: RawValueType::NumberValue, value: 200 },
998 );
999 append_inequal_cond(
1000 &mut instructions,
1001 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1002 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1003 );
1004 append_equal_cond(
1005 &mut instructions,
1006 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1007 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1008 );
1009
1010 verify_match_result(
1011 Ok(true),
1012 DecodedBindRules {
1013 symbol_table: symbol_table,
1014 instructions: instructions,
1015 decoded_instructions: vec![],
1016 debug_info: None,
1017 },
1018 &device_properties,
1019 );
1020 }
1021
1022 #[test]
1023 fn no_match_with_multiple_condition_statements() {
1024 let mut device_properties: DeviceProperties = HashMap::new();
1025 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1026 device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
1027 device_properties.insert(
1028 PropertyKey::StringKey("rail".to_string()),
1029 Symbol::StringValue("crake".to_string()),
1030 );
1031
1032 let mut symbol_table: HashMap<u32, String> = HashMap::new();
1033 symbol_table.insert(1, "crake".to_string());
1034 symbol_table.insert(2, "rail".to_string());
1035
1036 let mut instructions: Vec<u8> = vec![];
1037 append_equal_cond(
1038 &mut instructions,
1039 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1040 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1041 );
1042 append_equal_cond(
1043 &mut instructions,
1044 EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
1045 EncodedValue { value_type: RawValueType::NumberValue, value: 5000 },
1046 );
1047 append_inequal_cond(
1048 &mut instructions,
1049 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
1050 EncodedValue { value_type: RawValueType::NumberValue, value: 40 },
1051 );
1052
1053 verify_match_result(
1054 Ok(false),
1055 DecodedBindRules {
1056 symbol_table: symbol_table,
1057 instructions: instructions,
1058 decoded_instructions: vec![],
1059 debug_info: None,
1060 },
1061 &device_properties,
1062 );
1063 }
1064
1065 #[test]
1066 fn unconditional_jump() {
1067 let mut instructions: Vec<u8> = vec![];
1068 append_unconditional_jump(&mut instructions, ABORT_BYTES + COND_INST_BYTES);
1069 append_abort(&mut instructions);
1070 append_equal_cond(
1071 &mut instructions,
1072 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
1073 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1074 );
1075 append_jump_pad(&mut instructions);
1076
1077 verify_match_result(
1078 Ok(true),
1079 DecodedBindRules {
1080 symbol_table: HashMap::new(),
1081 instructions: instructions,
1082 decoded_instructions: vec![],
1083 debug_info: None,
1084 },
1085 &HashMap::new(),
1086 );
1087 }
1088
1089 #[test]
1090 fn jump_if_equal() {
1091 let mut symbol_table: HashMap<u32, String> = HashMap::new();
1092 symbol_table.insert(1, "whimbrel".to_string());
1093
1094 let mut instructions: Vec<u8> = vec![];
1095 append_jump_if_equal(
1096 &mut instructions,
1097 ABORT_BYTES * 2,
1098 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1099 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1100 );
1101 append_abort(&mut instructions);
1102 append_abort(&mut instructions);
1103 append_jump_pad(&mut instructions);
1104
1105 let mut device_properties: DeviceProperties = HashMap::new();
1106 device_properties
1107 .insert(PropertyKey::NumberKey(10), Symbol::StringValue("whimbrel".to_string()));
1108 verify_match_result(
1109 Ok(true),
1110 DecodedBindRules {
1111 symbol_table: symbol_table.clone(),
1112 instructions: instructions.clone(),
1113 decoded_instructions: vec![],
1114 debug_info: None,
1115 },
1116 &device_properties,
1117 );
1118
1119 let mut device_properties: DeviceProperties = HashMap::new();
1120 device_properties
1121 .insert(PropertyKey::NumberKey(10), Symbol::StringValue("godwit".to_string()));
1122 verify_match_result(
1123 Ok(false),
1124 DecodedBindRules {
1125 symbol_table: symbol_table.clone(),
1126 instructions: instructions,
1127 decoded_instructions: vec![],
1128 debug_info: None,
1129 },
1130 &device_properties,
1131 );
1132 }
1133
1134 #[test]
1135 fn jump_if_not_equal() {
1136 let mut instructions: Vec<u8> = vec![];
1137 append_jump_if_not_equal(
1138 &mut instructions,
1139 ABORT_BYTES * 2,
1140 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1141 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1142 );
1143 append_abort(&mut instructions);
1144 append_abort(&mut instructions);
1145 append_jump_pad(&mut instructions);
1146
1147 let mut device_properties: DeviceProperties = HashMap::new();
1148 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1149 verify_match_result(
1150 Ok(false),
1151 DecodedBindRules {
1152 symbol_table: HashMap::new(),
1153 instructions: instructions.clone(),
1154 decoded_instructions: vec![],
1155 debug_info: None,
1156 },
1157 &device_properties,
1158 );
1159
1160 let mut device_properties: DeviceProperties = HashMap::new();
1161 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(20));
1162 verify_match_result(
1163 Ok(true),
1164 DecodedBindRules {
1165 symbol_table: HashMap::new(),
1166 instructions: instructions,
1167 decoded_instructions: vec![],
1168 debug_info: None,
1169 },
1170 &device_properties,
1171 );
1172 }
1173
1174 #[test]
1175 fn no_jump_pad() {
1176 let mut device_properties: DeviceProperties = HashMap::new();
1177 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1178
1179 let mut instructions: Vec<u8> = vec![];
1180 append_jump_if_equal(
1181 &mut instructions,
1182 ABORT_BYTES,
1183 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1184 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1185 );
1186 append_abort(&mut instructions);
1187 append_abort(&mut instructions);
1188 verify_match_result(
1189 Err(BytecodeError::InvalidJumpLocation),
1190 DecodedBindRules {
1191 symbol_table: HashMap::new(),
1192 instructions: instructions,
1193 decoded_instructions: vec![],
1194 debug_info: None,
1195 },
1196 &device_properties,
1197 );
1198 }
1199
1200 #[test]
1201 fn jump_out_of_bounds() {
1202 let mut device_properties: DeviceProperties = HashMap::new();
1203 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1204
1205 let mut instructions: Vec<u8> = vec![];
1206 append_jump_if_equal(
1207 &mut instructions,
1208 ABORT_BYTES + JMP_PAD_BYTES + 1,
1209 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1210 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1211 );
1212 append_abort(&mut instructions);
1213 append_jump_pad(&mut instructions);
1214 verify_match_result(
1215 Err(BytecodeError::UnexpectedEnd),
1216 DecodedBindRules {
1217 symbol_table: HashMap::new(),
1218 instructions: instructions,
1219 decoded_instructions: vec![],
1220 debug_info: None,
1221 },
1222 &device_properties,
1223 );
1224 }
1225
1226 #[test]
1227 fn nested_jump_instructions() {
1228 let mut instructions: Vec<u8> = vec![];
1229 append_jump_if_equal(
1230 &mut instructions,
1231 ABORT_BYTES * 2 + UNCOND_JMP_BYTES + JMP_PAD_BYTES,
1232 EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1233 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1234 );
1235 append_unconditional_jump(&mut instructions, ABORT_BYTES);
1236 append_abort(&mut instructions);
1237 append_jump_pad(&mut instructions);
1238 append_abort(&mut instructions);
1239 append_jump_pad(&mut instructions);
1240
1241 let mut device_properties: DeviceProperties = HashMap::new();
1242 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1243 verify_match_result(
1244 Ok(true),
1245 DecodedBindRules {
1246 symbol_table: HashMap::new(),
1247 instructions: instructions.clone(),
1248 decoded_instructions: vec![],
1249 debug_info: None,
1250 },
1251 &device_properties,
1252 );
1253
1254 let mut device_properties: DeviceProperties = HashMap::new();
1255 device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(200));
1256 device_properties.insert(
1257 PropertyKey::StringKey("kingfisher".to_string()),
1258 Symbol::StringValue("kookaburra".to_string()),
1259 );
1260 verify_match_result(
1261 Ok(false),
1262 DecodedBindRules {
1263 symbol_table: HashMap::new(),
1264 instructions: instructions,
1265 decoded_instructions: vec![],
1266 debug_info: None,
1267 },
1268 &device_properties,
1269 );
1270 }
1271
1272 #[test]
1273 fn complex_mix_of_bind_rules() {
1274 let mut symbol_table: HashMap<u32, String> = HashMap::new();
1275 symbol_table.insert(1, "kingfisher".to_string());
1276 symbol_table.insert(2, "kookaburra".to_string());
1277
1278 let mut instructions: Vec<u8> = vec![];
1279 append_jump_if_equal(
1280 &mut instructions,
1281 COND_INST_BYTES + ABORT_BYTES,
1282 EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
1283 EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
1284 );
1285 append_equal_cond(
1286 &mut instructions,
1287 EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
1288 EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1289 );
1290 append_abort(&mut instructions);
1291 append_jump_pad(&mut instructions);
1292 append_unconditional_jump(&mut instructions, COND_JMP_BYTES + ABORT_BYTES);
1293 append_jump_if_not_equal(
1294 &mut instructions,
1295 ABORT_BYTES + JMP_PAD_BYTES + COND_INST_BYTES,
1296 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1297 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1298 );
1299 append_abort(&mut instructions);
1300 append_jump_pad(&mut instructions);
1301 append_inequal_cond(
1302 &mut instructions,
1303 EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
1304 EncodedValue { value_type: RawValueType::NumberValue, value: 50 },
1305 );
1306 append_jump_pad(&mut instructions);
1307 append_equal_cond(
1308 &mut instructions,
1309 EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1310 EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1311 );
1312
1313 let mut device_properties: DeviceProperties = HashMap::new();
1314 device_properties.insert(
1315 PropertyKey::StringKey("kingfisher".to_string()),
1316 Symbol::StringValue("kookaburra".to_string()),
1317 );
1318 device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(9));
1319 device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(100));
1320 device_properties.insert(PropertyKey::NumberKey(5), Symbol::BoolValue(true));
1321
1322 verify_match_result(
1323 Ok(true),
1324 DecodedBindRules {
1325 symbol_table: symbol_table,
1326 instructions: instructions,
1327 decoded_instructions: vec![],
1328 debug_info: None,
1329 },
1330 &device_properties,
1331 );
1332 }
1333}