Skip to main content

bind/interpreter/
match_bind.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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// TODO(https://fxbug.dev/42151229): Currently, the driver manager only supports number-based
33// device properties. It will support string-based properties soon. We should
34// support other device property types in the future.
35#[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                    // No-op.
135                }
136            };
137        }
138
139        Ok(true)
140    }
141
142    // Evaluates a conditional instruction and returns false if the condition failed.
143    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        // Skip through the bytes by the amount in the offset.
162        for _ in 0..offset {
163            next_u8(&mut self.iter)?;
164        }
165
166        // Verify that the next instruction is a jump pad.
167        if *next_u8(&mut self.iter)? != RawOp::JumpLandPad as u8 {
168            return Err(BytecodeError::InvalidJumpLocation);
169        }
170
171        Ok(())
172    }
173
174    // Read in two values and evaluate them based on the given condition.
175    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 the node properties doesn't contain an integer key, try to convert the
188        // integer key to a deprecated string key, and check if the node properties
189        // contain that.
190        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    // Read in the next u8 as the value type and the next u32 as the value. Convert the value
205    // into a RawSymbol.
206    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    // If either side is an EnumValue type, treat it as a StringValue type for the comparison.
241    // This is because both of these types contain a string inside of them and as long as that
242    // value is the same, then the equality is satisfied.
243    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
265// Return true if the bytecode matches the device properties. The bytecode
266// is for a non-composite driver.
267pub 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
280// Return true if the bind rules matches the device properties.
281pub 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    // Constants representing the number of bytes in an operand and value.
298    const OP_BYTES: u32 = 1;
299    const VALUE_BYTES: u32 = 5;
300    const OFFSET_BYTES: u32 = 4;
301
302    // Constants representing the number of bytes in each instruction.
303    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        // The condition statement should match the device properties.
411        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        // The condition should fail since the device property has a different value.
429        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        // The condition should fail since the property is missing from device properties.
447        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        // The condition statement should match the string device properties.
484        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        // The condition should fail since the string device property has a different value.
507        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        // The condition should fail since the property is missing from string device properties.
525        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        // The condition should match since the device property has a different value.
550        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        // The condition should match since the device properties doesn't contain the property.
568        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        // The condition should fail since the device properties matches the value.
586        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        // The condition should match since the string device property has a different value.
617        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        // The condition should match since the string device properties doesn't contain the
635        // property.
636        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        // The condition should fail since the string device properties matches the value.
654        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, /* BIND_PROTOCOL */
790            },
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, /* BIND_AUTOBIND */
798            },
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}