Browse Source

Implement comparison between strings and buffers

Isaac Woods 4 years ago
parent
commit
6d2045de3a
1 changed files with 45 additions and 3 deletions
  1. 45 3
      aml/src/value.rs

+ 45 - 3
aml/src/value.rs

@@ -237,6 +237,24 @@ impl AmlValue {
         }
     }
 
+    pub fn as_buffer(&self, context: &AmlContext) -> Result<Vec<u8>, AmlError> {
+        match self {
+            AmlValue::Buffer { ref bytes, .. } => Ok(bytes.clone()),
+            // TODO: implement conversion of String and Integer to Buffer
+            AmlValue::Field { .. } => self.read_field(context)?.as_buffer(context),
+            _ => Err(AmlError::IncompatibleValueConversion),
+        }
+    }
+
+    pub fn as_string(&self, context: &AmlContext) -> Result<String, AmlError> {
+        match self {
+            AmlValue::String(ref string) => Ok(string.clone()),
+            // TODO: implement conversion of Buffer to String
+            AmlValue::Field { .. } => self.read_field(context)?.as_string(context),
+            _ => Err(AmlError::IncompatibleValueConversion),
+        }
+    }
+
     /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
     /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
     /// `StatusObject::default()`.
@@ -391,15 +409,16 @@ impl AmlValue {
     ///    - `Integer`s are simply compared by numeric comparison
     ///    - `String`s and `Buffer`s are compared lexicographically - `other` is compared byte-wise until a byte
     ///      is discovered that is either less or greater than the corresponding byte of `self`. If the bytes are
-    ///      identical, the lengths are compared.
+    ///      identical, the lengths are compared. Luckily, the Rust standard library implements lexicographic
+    ///      comparison of strings and `[u8]` for us already.
     pub fn cmp(&self, other: AmlValue, context: &mut AmlContext) -> Result<cmp::Ordering, AmlError> {
         let self_inner =
             if self.type_of() == AmlType::FieldUnit { self.read_field(context)? } else { self.clone() };
 
         match self_inner.type_of() {
             AmlType::Integer => Ok(self.as_integer(context)?.cmp(&other.as_integer(context)?)),
-            AmlType::Buffer => unimplemented!(),
-            AmlType::String => unimplemented!(),
+            AmlType::Buffer => Ok(self.as_buffer(context)?.cmp(&other.as_buffer(context)?)),
+            AmlType::String => Ok(self.as_string(context)?.cmp(&other.as_string(context)?)),
             typ => Err(AmlError::TypeCannotBeCompared(typ)),
         }
     }
@@ -448,3 +467,26 @@ impl Args {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{test_utils::*, AmlError};
+    use core::cmp::Ordering;
+
+    #[test]
+    fn test_object_cmp() {
+        let mut context = make_test_context();
+
+        assert_eq!(AmlValue::Integer(76).cmp(AmlValue::Integer(89), &mut context), Ok(Ordering::Less));
+        assert_eq!(AmlValue::Integer(11).cmp(AmlValue::Integer(11), &mut context), Ok(Ordering::Equal));
+        assert_eq!(AmlValue::Integer(8362836690).cmp(AmlValue::Integer(1), &mut context), Ok(Ordering::Greater));
+
+        assert_eq!(
+            AmlValue::Integer(4).cmp(AmlValue::Boolean(true), &mut context),
+            Err(AmlError::IncompatibleValueConversion)
+        );
+
+        // TODO: test the other combinations too, as well as conversions to the correct types for the second operand
+    }
+}