|
@@ -23,82 +23,157 @@ impl AmlHandle {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
+pub enum LevelType {
|
|
|
+ Scope,
|
|
|
+ Device,
|
|
|
+ /// A legacy `Processor` object's sub-objects are stored in a level of this type. Modern tables define
|
|
|
+ /// processors as `Device`s.
|
|
|
+ Processor,
|
|
|
+ /// A level of this type is created at the same path as the name of a method when it is invoked. It can be
|
|
|
+ /// used by the method to store local variables.
|
|
|
+ MethodLocals,
|
|
|
+}
|
|
|
+
|
|
|
+pub struct NamespaceLevel {
|
|
|
+ typ: LevelType,
|
|
|
+ children: BTreeMap<NameSeg, NamespaceLevel>,
|
|
|
+ values: BTreeMap<NameSeg, AmlHandle>,
|
|
|
+}
|
|
|
+
|
|
|
+impl NamespaceLevel {
|
|
|
+ pub(crate) fn new(typ: LevelType) -> NamespaceLevel {
|
|
|
+ NamespaceLevel { typ, children: BTreeMap::new(), values: BTreeMap::new() }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
pub struct Namespace {
|
|
|
/// This is a running count of ids, which are never reused. This is incremented every time we
|
|
|
/// add a new object to the namespace. We can then remove objects, freeing their memory, without
|
|
|
/// risking using the same id for two objects.
|
|
|
next_handle: AmlHandle,
|
|
|
|
|
|
- /// This maps handles to actual values, and is used to access the actual AML values.
|
|
|
+ /// This maps handles to actual values, and is used to access the actual AML values. When removing a value
|
|
|
+ /// from the object map, care must be taken to also remove references to its handle in the level data
|
|
|
+ /// structure, as invalid handles will cause panics.
|
|
|
object_map: BTreeMap<AmlHandle, AmlValue>,
|
|
|
|
|
|
- /// This maps names to handles, and should be used when you don't already have the handle to a
|
|
|
- /// value.
|
|
|
- // XXX: in the future, this could be replaced with a better data structure that doesn't store
|
|
|
- // the entire name for each id. Instead, it would be a tree-like structure that stores each
|
|
|
- // name segment, with a list of objects and their names, and a list of child scopes at that
|
|
|
- // level.
|
|
|
- name_map: BTreeMap<AmlName, AmlHandle>,
|
|
|
+ /// Holds the first level of the namespace - containing items such as `\_SB`. Subsequent levels are held
|
|
|
+ /// recursively inside this structure. It holds handles to references, which need to be indexed into
|
|
|
+ /// `object_map` to acctually access the object.
|
|
|
+ root: NamespaceLevel,
|
|
|
}
|
|
|
|
|
|
impl Namespace {
|
|
|
pub fn new() -> Namespace {
|
|
|
- Namespace { next_handle: AmlHandle(0), object_map: BTreeMap::new(), name_map: BTreeMap::new() }
|
|
|
+ Namespace {
|
|
|
+ next_handle: AmlHandle(0),
|
|
|
+ object_map: BTreeMap::new(),
|
|
|
+ root: NamespaceLevel::new(LevelType::Scope),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add a new level to the namespace. A "level" is named by a single `NameSeg`, and can contain values, and
|
|
|
+ /// also other further sub-levels. Once a level has been created, AML values can be added to it with
|
|
|
+ /// `add_value`.
|
|
|
+ ///
|
|
|
+ /// ### Note
|
|
|
+ /// At first glance, you might expect `DefDevice` to add a value of type `Device`. However, because all
|
|
|
+ /// `Devices` do is hold other values, we model them as namespace levels, and so they must be created
|
|
|
+ /// accordingly.
|
|
|
+ pub fn add_level(&mut self, path: AmlName, typ: LevelType) -> Result<(), AmlError> {
|
|
|
+ assert!(path.is_absolute());
|
|
|
+ let path = path.normalize()?;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We need to handle a special case here: if a `Scope(\) { ... }` appears in the AML, the parser will
|
|
|
+ * try and recreate the root scope. Instead of handling this specially in the parser, we just
|
|
|
+ * return nicely here.
|
|
|
+ */
|
|
|
+ if path != AmlName::root() {
|
|
|
+ let (level, last_seg) = self.get_level_for_path_mut(&path)?;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the level has already been added, we don't need to add it again. The parser can try to add it
|
|
|
+ * multiple times if the ASL contains multiple blocks that add to the same scope/device.
|
|
|
+ */
|
|
|
+ if !level.children.contains_key(&last_seg) {
|
|
|
+ level.children.insert(last_seg, NamespaceLevel::new(typ));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn remove_level(&mut self, path: AmlName) -> Result<(), AmlError> {
|
|
|
+ assert!(path.is_absolute());
|
|
|
+ let path = path.normalize()?;
|
|
|
+
|
|
|
+ if path != AmlName::root() {
|
|
|
+ let (level, last_seg) = self.get_level_for_path_mut(&path)?;
|
|
|
+
|
|
|
+ match level.children.remove(&last_seg) {
|
|
|
+ Some(_) => Ok(()),
|
|
|
+ None => Err(AmlError::LevelDoesNotExist(path)),
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Err(AmlError::TriedToRemoveRootNamespace)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Add a value to the namespace at the given path, which must be a normalized, absolute AML
|
|
|
/// name. If you want to add at a path relative to a given scope, use `add_at_resolved_path`
|
|
|
/// instead.
|
|
|
- pub fn add(&mut self, path: AmlName, value: AmlValue) -> Result<AmlHandle, AmlError> {
|
|
|
+ pub fn add_value(&mut self, path: AmlName, value: AmlValue) -> Result<AmlHandle, AmlError> {
|
|
|
assert!(path.is_absolute());
|
|
|
- assert!(path.is_normal());
|
|
|
-
|
|
|
- if self.name_map.contains_key(&path) {
|
|
|
- return Err(AmlError::NameCollision(path.clone()));
|
|
|
- }
|
|
|
+ let path = path.normalize()?;
|
|
|
|
|
|
let handle = self.next_handle;
|
|
|
self.next_handle.increment();
|
|
|
-
|
|
|
self.object_map.insert(handle, value);
|
|
|
- self.name_map.insert(path, handle);
|
|
|
|
|
|
- Ok(handle)
|
|
|
+ let (level, last_seg) = self.get_level_for_path_mut(&path)?;
|
|
|
+ match level.values.insert(last_seg, handle) {
|
|
|
+ None => Ok(handle),
|
|
|
+ Some(_) => Err(AmlError::NameCollision(path)),
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Helper method for adding a value to the namespace at a path that is relative to the given
|
|
|
/// scope. This operation involves a lot of error handling in parts of the parser, so is
|
|
|
/// encapsulated here.
|
|
|
- pub fn add_at_resolved_path(
|
|
|
+ pub fn add_value_at_resolved_path(
|
|
|
&mut self,
|
|
|
path: AmlName,
|
|
|
scope: &AmlName,
|
|
|
value: AmlValue,
|
|
|
) -> Result<AmlHandle, AmlError> {
|
|
|
- self.add(path.resolve(scope)?, value)
|
|
|
+ self.add_value(path.resolve(scope)?, value)
|
|
|
}
|
|
|
|
|
|
pub fn get(&self, handle: AmlHandle) -> Result<&AmlValue, AmlError> {
|
|
|
- self.object_map.get(&handle).ok_or(AmlError::HandleDoesNotExist(handle))
|
|
|
+ Ok(self.object_map.get(&handle).unwrap())
|
|
|
}
|
|
|
|
|
|
- pub fn get_by_path(&self, path: &AmlName) -> Result<&AmlValue, AmlError> {
|
|
|
- let handle = *self.name_map.get(path).ok_or(AmlError::ObjectDoesNotExist(path.as_string()))?;
|
|
|
- self.get(handle).map_err(|_| AmlError::ObjectDoesNotExist(path.as_string()))
|
|
|
+ pub fn get_mut(&mut self, handle: AmlHandle) -> Result<&mut AmlValue, AmlError> {
|
|
|
+ Ok(self.object_map.get_mut(&handle).unwrap())
|
|
|
}
|
|
|
|
|
|
- pub fn get_mut(&mut self, handle: AmlHandle) -> Result<&mut AmlValue, AmlError> {
|
|
|
- self.object_map.get_mut(&handle).ok_or(AmlError::HandleDoesNotExist(handle))
|
|
|
+ pub fn get_by_path(&self, path: &AmlName) -> Result<&AmlValue, AmlError> {
|
|
|
+ let (level, last_seg) = self.get_level_for_path(path)?;
|
|
|
+ let &handle = level.values.get(&last_seg).ok_or(AmlError::ValueDoesNotExist(path.clone()))?;
|
|
|
+ Ok(self.get(handle).unwrap())
|
|
|
}
|
|
|
|
|
|
pub fn get_by_path_mut(&mut self, path: &AmlName) -> Result<&mut AmlValue, AmlError> {
|
|
|
- let handle = *self.name_map.get(path).ok_or(AmlError::ObjectDoesNotExist(path.as_string()))?;
|
|
|
- self.get_mut(handle).map_err(|_| AmlError::ObjectDoesNotExist(path.as_string()))
|
|
|
+ let (level, last_seg) = self.get_level_for_path(path)?;
|
|
|
+ let &handle = level.values.get(&last_seg).ok_or(AmlError::ValueDoesNotExist(path.clone()))?;
|
|
|
+ Ok(self.get_mut(handle).unwrap())
|
|
|
}
|
|
|
|
|
|
- /// Search for an object at the given path of the namespace, applying the search rules
|
|
|
- /// described in §5.3 of the ACPI specification, if they are applicable. Returns the resolved name, and the
|
|
|
- /// handle of the first valid object, if found.
|
|
|
+ /// Search for an object at the given path of the namespace, applying the search rules described in §5.3 of the
|
|
|
+ /// ACPI specification, if they are applicable. Returns the resolved name, and the handle of the first valid
|
|
|
+ /// object, if found.
|
|
|
pub fn search(&self, path: &AmlName, starting_scope: &AmlName) -> Result<(AmlName, AmlHandle), AmlError> {
|
|
|
if path.search_rules_apply() {
|
|
|
/*
|
|
@@ -111,40 +186,148 @@ impl Namespace {
|
|
|
loop {
|
|
|
// Search for the name at this namespace level. If we find it, we're done.
|
|
|
let name = path.resolve(&scope)?;
|
|
|
- if let Some(handle) = self.name_map.get(&name) {
|
|
|
- return Ok((name, *handle));
|
|
|
+ match self.get_level_for_path(&name) {
|
|
|
+ Ok((level, last_seg)) => {
|
|
|
+ if let Some(&handle) = level.values.get(&last_seg) {
|
|
|
+ return Ok((name, handle));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This error is caught specially to avoid a case that seems bizzare but is quite useful - when
|
|
|
+ * the passed starting scope doesn't exist. Certain methods return values that reference names
|
|
|
+ * from the point of view of the method, so it makes sense for the starting scope to be inside
|
|
|
+ * the method. However, because we have destroyed all the objects created by the method
|
|
|
+ * dynamically, the level no longer exists.
|
|
|
+ *
|
|
|
+ * To avoid erroring here, we simply continue to the parent scope. If the whole scope doesn't
|
|
|
+ * exist, this will error when we get to the root, so this seems unlikely to introduce bugs.
|
|
|
+ */
|
|
|
+ Err(AmlError::LevelDoesNotExist(_)) => (),
|
|
|
+ Err(err) => return Err(err),
|
|
|
}
|
|
|
|
|
|
- // If we don't find it, go up a level in the namespace and search for it there,
|
|
|
- // recursively.
|
|
|
+ // If we don't find it, go up a level in the namespace and search for it there recursively
|
|
|
match scope.parent() {
|
|
|
Ok(parent) => scope = parent,
|
|
|
// If we still haven't found the value and have run out of parents, return `None`.
|
|
|
- Err(AmlError::RootHasNoParent) => return Err(AmlError::ObjectDoesNotExist(path.as_string())),
|
|
|
+ Err(AmlError::RootHasNoParent) => return Err(AmlError::ValueDoesNotExist(path.clone())),
|
|
|
Err(err) => return Err(err),
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
// If search rules don't apply, simply resolve it against the starting scope
|
|
|
let name = path.resolve(starting_scope)?;
|
|
|
- Ok((
|
|
|
- name,
|
|
|
- self.name_map
|
|
|
- .get(&path.resolve(starting_scope)?)
|
|
|
- .map(|&handle| handle)
|
|
|
- .ok_or(AmlError::ObjectDoesNotExist(path.as_string()))?,
|
|
|
- ))
|
|
|
+ let (level, last_seg) = self.get_level_for_path(&path.resolve(starting_scope)?)?;
|
|
|
+
|
|
|
+ if let Some(&handle) = level.values.get(&last_seg) {
|
|
|
+ Ok((name, handle))
|
|
|
+ } else {
|
|
|
+ Err(AmlError::ValueDoesNotExist(path.clone()))
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ pub fn search_for_level(&self, level_name: &AmlName, starting_scope: &AmlName) -> Result<AmlName, AmlError> {
|
|
|
+ if level_name.search_rules_apply() {
|
|
|
+ let mut scope = starting_scope.clone().normalize()?;
|
|
|
+ assert!(scope.is_absolute());
|
|
|
+
|
|
|
+ loop {
|
|
|
+ let name = level_name.resolve(&scope)?;
|
|
|
+ if let Ok((level, last_seg)) = self.get_level_for_path(&name) {
|
|
|
+ if let Some(_) = level.children.get(&last_seg) {
|
|
|
+ return Ok(name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // If we don't find it, move the scope up a level and search for it there recursively
|
|
|
+ match scope.parent() {
|
|
|
+ Ok(parent) => scope = parent,
|
|
|
+ Err(AmlError::RootHasNoParent) => return Err(AmlError::LevelDoesNotExist(level_name.clone())),
|
|
|
+ Err(err) => return Err(err),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Ok(level_name.clone())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn get_level_for_path(&self, path: &AmlName) -> Result<(&NamespaceLevel, NameSeg), AmlError> {
|
|
|
+ let (last_seg, levels) = path.0[1..].split_last().unwrap();
|
|
|
+ let last_seg = last_seg.as_segment().unwrap();
|
|
|
+
|
|
|
+ // TODO: this helps with diagnostics, but requires a heap allocation just in case we need to error.
|
|
|
+ let mut traversed_path = AmlName::root();
|
|
|
+
|
|
|
+ let mut current_level = &self.root;
|
|
|
+ for level in levels {
|
|
|
+ traversed_path.0.push(*level);
|
|
|
+ current_level = current_level
|
|
|
+ .children
|
|
|
+ .get(&level.as_segment().unwrap())
|
|
|
+ .ok_or(AmlError::LevelDoesNotExist(traversed_path.clone()))?;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok((current_level, last_seg))
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Split an absolute path into a bunch of level segments (used to traverse the level data structure), and a
|
|
|
+ /// last segment to index into that level. This must not be called on `\\`.
|
|
|
+ fn get_level_for_path_mut(&mut self, path: &AmlName) -> Result<(&mut NamespaceLevel, NameSeg), AmlError> {
|
|
|
+ let (last_seg, levels) = path.0[1..].split_last().unwrap();
|
|
|
+ let last_seg = last_seg.as_segment().unwrap();
|
|
|
+
|
|
|
+ // TODO: this helps with diagnostics, but requires a heap allocation just in case we need to error. We can
|
|
|
+ // improve this by changing the `levels` interation into an `enumerate()`, and then using the index to
|
|
|
+ // create the correct path on the error path
|
|
|
+ let mut traversed_path = AmlName::root();
|
|
|
+
|
|
|
+ let mut current_level = &mut self.root;
|
|
|
+ for level in levels {
|
|
|
+ traversed_path.0.push(*level);
|
|
|
+ current_level = current_level
|
|
|
+ .children
|
|
|
+ .get_mut(&level.as_segment().unwrap())
|
|
|
+ .ok_or(AmlError::LevelDoesNotExist(traversed_path.clone()))?;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok((current_level, last_seg))
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl fmt::Debug for Namespace {
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
- for (name, handle) in self.name_map.iter() {
|
|
|
- write!(f, "{}: {:?}\n", name, self.object_map.get(handle).unwrap())?;
|
|
|
- }
|
|
|
+ const INDENT_PER_LEVEL: usize = 4;
|
|
|
+
|
|
|
+ fn print_level(
|
|
|
+ namespace: &Namespace,
|
|
|
+ f: &mut fmt::Formatter<'_>,
|
|
|
+ level_name: &str,
|
|
|
+ level: &NamespaceLevel,
|
|
|
+ indent: usize,
|
|
|
+ ) -> fmt::Result {
|
|
|
+ writeln!(f, "{:indent$}{}:", "", level_name, indent = indent)?;
|
|
|
+
|
|
|
+ for (name, handle) in level.values.iter() {
|
|
|
+ writeln!(
|
|
|
+ f,
|
|
|
+ "{:indent$}{}: {:?}",
|
|
|
+ "",
|
|
|
+ name.as_str(),
|
|
|
+ namespace.object_map.get(handle).unwrap(),
|
|
|
+ indent = indent + INDENT_PER_LEVEL
|
|
|
+ )?;
|
|
|
+ }
|
|
|
|
|
|
- Ok(())
|
|
|
+ for (name, sub_level) in level.children.iter() {
|
|
|
+ print_level(namespace, f, name.as_str(), sub_level, indent + INDENT_PER_LEVEL)?;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+ };
|
|
|
+
|
|
|
+ print_level(self, f, "\\", &self.root, 0)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -228,7 +411,15 @@ impl AmlName {
|
|
|
/// Normalize an AML path, resolving prefix chars. Returns `AmlError::InvalidNormalizedName` if the path
|
|
|
/// normalizes to an invalid path (e.g. `\^_FOO`)
|
|
|
pub fn normalize(self) -> Result<AmlName, AmlError> {
|
|
|
- Ok(AmlName(self.0.iter().try_fold(alloc::vec![], |mut name, &component| match component {
|
|
|
+ /*
|
|
|
+ * If the path is already normal, just return it as-is. This avoids an unneccessary heap allocation and
|
|
|
+ * free.
|
|
|
+ */
|
|
|
+ if self.is_normal() {
|
|
|
+ return Ok(self);
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(AmlName(self.0.iter().try_fold(Vec::new(), |mut name, &component| match component {
|
|
|
seg @ NameComponent::Segment(_) => {
|
|
|
name.push(seg);
|
|
|
Ok(name)
|
|
@@ -294,6 +485,15 @@ pub enum NameComponent {
|
|
|
Segment(NameSeg),
|
|
|
}
|
|
|
|
|
|
+impl NameComponent {
|
|
|
+ pub fn as_segment(self) -> Result<NameSeg, ()> {
|
|
|
+ match self {
|
|
|
+ NameComponent::Segment(seg) => Ok(seg),
|
|
|
+ NameComponent::Root | NameComponent::Prefix => Err(()),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
use super::*;
|
|
@@ -388,4 +588,80 @@ mod tests {
|
|
|
assert_eq!(AmlName::from_str("\\_SB.PCI0").unwrap().parent(), Ok(AmlName::from_str("\\_SB").unwrap()));
|
|
|
assert_eq!(AmlName::from_str("\\_SB.PCI0").unwrap().parent().unwrap().parent(), Ok(AmlName::root()));
|
|
|
}
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_namespace() {
|
|
|
+ let mut namespace = Namespace::new();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This should succeed but do nothing.
|
|
|
+ */
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add `\_SB`, also testing that adding a level twice succeeds.
|
|
|
+ */
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\_SB").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\_SB").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add a device under a level that already exists.
|
|
|
+ */
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\_SB.PCI0").unwrap(), LevelType::Device), Ok(()));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add some deeper scopes.
|
|
|
+ */
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\FOO").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\FOO.BAR").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\FOO.BAR.BAZ").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\FOO.BAR.BAZ").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+ assert_eq!(namespace.add_level(AmlName::from_str("\\FOO.BAR.BAZ.QUX").unwrap(), LevelType::Scope), Ok(()));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add some things to the scopes to query later.
|
|
|
+ */
|
|
|
+ assert!(namespace.add_value(AmlName::from_str("\\MOO").unwrap(), AmlValue::Boolean(true)).is_ok());
|
|
|
+ assert!(namespace.add_value(AmlName::from_str("\\FOO.BAR.A").unwrap(), AmlValue::Integer(12345)).is_ok());
|
|
|
+ assert!(namespace.add_value(AmlName::from_str("\\FOO.BAR.B").unwrap(), AmlValue::Integer(6)).is_ok());
|
|
|
+ assert!(namespace
|
|
|
+ .add_value(AmlName::from_str("\\FOO.BAR.C").unwrap(), AmlValue::String(String::from("hello, world!")))
|
|
|
+ .is_ok());
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Get objects using their absolute paths.
|
|
|
+ */
|
|
|
+ assert_eq!(namespace.get_by_path(&AmlName::from_str("\\MOO").unwrap()), Ok(&AmlValue::Boolean(true)));
|
|
|
+ assert_eq!(
|
|
|
+ namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.A").unwrap()),
|
|
|
+ Ok(&AmlValue::Integer(12345))
|
|
|
+ );
|
|
|
+ assert_eq!(namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.B").unwrap()), Ok(&AmlValue::Integer(6)));
|
|
|
+ assert_eq!(
|
|
|
+ namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.C").unwrap()),
|
|
|
+ Ok(&AmlValue::String(String::from("hello, world!")))
|
|
|
+ );
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Search for some objects that should use search rules.
|
|
|
+ */
|
|
|
+ {
|
|
|
+ let (name, _) = namespace
|
|
|
+ .search(&AmlName::from_str("MOO").unwrap(), &AmlName::from_str("\\FOO.BAR.BAZ").unwrap())
|
|
|
+ .unwrap();
|
|
|
+ assert_eq!(name, AmlName::from_str("\\MOO").unwrap());
|
|
|
+ }
|
|
|
+ {
|
|
|
+ let (name, _) = namespace
|
|
|
+ .search(&AmlName::from_str("A").unwrap(), &AmlName::from_str("\\FOO.BAR").unwrap())
|
|
|
+ .unwrap();
|
|
|
+ assert_eq!(name, AmlName::from_str("\\FOO.BAR.A").unwrap());
|
|
|
+ }
|
|
|
+ {
|
|
|
+ let (name, _) = namespace
|
|
|
+ .search(&AmlName::from_str("A").unwrap(), &AmlName::from_str("\\FOO.BAR.BAZ.QUX").unwrap())
|
|
|
+ .unwrap();
|
|
|
+ assert_eq!(name, AmlName::from_str("\\FOO.BAR.A").unwrap());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|