use crate::{name_object::NameSeg, value::AmlValue, AmlError};
use alloc::{
collections::BTreeMap,
string::{String, ToString},
vec::Vec,
};
use core::fmt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct AmlHandle(u32);
impl AmlHandle {
pub(self) fn increment(&mut self) {
self.0 += 1;
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum LevelType {
Scope,
Device,
Processor,
MethodLocals,
}
#[derive(Clone, Debug)]
pub struct NamespaceLevel {
pub typ: LevelType,
pub children: BTreeMap<NameSeg, NamespaceLevel>,
pub values: BTreeMap<NameSeg, AmlHandle>,
}
impl NamespaceLevel {
pub(crate) fn new(typ: LevelType) -> NamespaceLevel {
NamespaceLevel { typ, children: BTreeMap::new(), values: BTreeMap::new() }
}
}
#[derive(Clone)]
pub struct Namespace {
next_handle: AmlHandle,
object_map: BTreeMap<AmlHandle, AmlValue>,
root: NamespaceLevel,
}
impl Namespace {
pub fn new() -> Namespace {
Namespace {
next_handle: AmlHandle(0),
object_map: BTreeMap::new(),
root: NamespaceLevel::new(LevelType::Scope),
}
}
pub fn add_level(&mut self, path: AmlName, typ: LevelType) -> 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)?;
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)
}
}
pub fn add_value(&mut self, path: AmlName, value: AmlValue) -> Result<AmlHandle, AmlError> {
assert!(path.is_absolute());
let path = path.normalize()?;
let handle = self.next_handle;
self.next_handle.increment();
self.object_map.insert(handle, value);
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)),
}
}
pub fn add_value_at_resolved_path(
&mut self,
path: AmlName,
scope: &AmlName,
value: AmlValue,
) -> Result<AmlHandle, AmlError> {
self.add_value(path.resolve(scope)?, value)
}
pub fn get(&self, handle: AmlHandle) -> Result<&AmlValue, AmlError> {
Ok(self.object_map.get(&handle).unwrap())
}
pub fn get_mut(&mut self, handle: AmlHandle) -> Result<&mut AmlValue, AmlError> {
Ok(self.object_map.get_mut(&handle).unwrap())
}
pub fn get_handle(&self, path: &AmlName) -> Result<AmlHandle, AmlError> {
let (level, last_seg) = self.get_level_for_path(path)?;
Ok(*level.values.get(&last_seg).ok_or(AmlError::ValueDoesNotExist(path.clone()))?)
}
pub fn get_by_path(&self, path: &AmlName) -> Result<&AmlValue, AmlError> {
let handle = self.get_handle(path)?;
Ok(self.get(handle).unwrap())
}
pub fn get_by_path_mut(&mut self, path: &AmlName) -> Result<&mut AmlValue, AmlError> {
let handle = self.get_handle(path)?;
Ok(self.get_mut(handle).unwrap())
}
pub fn search(&self, path: &AmlName, starting_scope: &AmlName) -> Result<(AmlName, AmlHandle), AmlError> {
if path.search_rules_apply() {
let mut scope = starting_scope.clone();
assert!(scope.is_absolute());
loop {
let name = path.resolve(&scope)?;
match self.get_level_for_path(&name) {
Ok((level, last_seg)) => {
if let Some(&handle) = level.values.get(&last_seg) {
return Ok((name, handle));
}
}
Err(AmlError::LevelDoesNotExist(_)) => (),
Err(err) => return Err(err),
}
match scope.parent() {
Ok(parent) => scope = parent,
Err(AmlError::RootHasNoParent) => return Err(AmlError::ValueDoesNotExist(path.clone())),
Err(err) => return Err(err),
}
}
} else {
let name = path.resolve(starting_scope)?;
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);
}
}
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> {
assert_ne!(*path, AmlName::root());
let (last_seg, levels) = path.0[1..].split_last().unwrap();
let last_seg = last_seg.as_segment().unwrap();
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))
}
fn get_level_for_path_mut(&mut self, path: &AmlName) -> Result<(&mut NamespaceLevel, NameSeg), AmlError> {
assert_ne!(*path, AmlName::root());
let (last_seg, levels) = path.0[1..].split_last().unwrap();
let last_seg = last_seg.as_segment().unwrap();
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))
}
pub fn traverse<F>(&mut self, mut f: F) -> Result<(), AmlError>
where
F: FnMut(&AmlName, &NamespaceLevel) -> Result<bool, AmlError>,
{
fn traverse_level<F>(level: &NamespaceLevel, scope: &AmlName, f: &mut F) -> Result<(), AmlError>
where
F: FnMut(&AmlName, &NamespaceLevel) -> Result<bool, AmlError>,
{
for (name, ref child) in level.children.iter() {
let name = AmlName::from_name_seg(*name).resolve(scope)?;
if f(&name, child)? {
traverse_level(child, &name, f)?;
}
}
Ok(())
}
if f(&AmlName::root(), &self.root)? {
traverse_level(&self.root, &AmlName::root(), &mut f)?;
}
Ok(())
}
}
impl fmt::Debug for Namespace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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
)?;
}
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)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct AmlName(Vec<NameComponent>);
impl AmlName {
pub fn root() -> AmlName {
AmlName(alloc::vec![NameComponent::Root])
}
pub fn from_name_seg(seg: NameSeg) -> AmlName {
AmlName(alloc::vec![NameComponent::Segment(seg)])
}
pub fn from_components(components: Vec<NameComponent>) -> AmlName {
assert!(components.len() > 0);
AmlName(components)
}
pub fn from_str(mut string: &str) -> Result<AmlName, AmlError> {
if string.len() == 0 {
return Err(AmlError::EmptyNamesAreInvalid);
}
let mut components = Vec::new();
if string.starts_with('\\') {
components.push(NameComponent::Root);
string = &string[1..];
}
if string.len() > 0 {
for mut part in string.split('.') {
while part.starts_with('^') {
components.push(NameComponent::Prefix);
part = &part[1..];
}
components.push(NameComponent::Segment(NameSeg::from_str(part)?));
}
}
Ok(AmlName(components))
}
pub fn as_string(&self) -> String {
self.0
.iter()
.fold(String::new(), |name, component| match component {
NameComponent::Root => name + "\\",
NameComponent::Prefix => name + "^",
NameComponent::Segment(seg) => name + seg.as_str() + ".",
})
.trim_end_matches('.')
.to_string()
}
pub fn is_normal(&self) -> bool {
!self.0.contains(&NameComponent::Prefix)
}
pub fn is_absolute(&self) -> bool {
self.0.first() == Some(&NameComponent::Root)
}
pub fn search_rules_apply(&self) -> bool {
if self.0.len() != 1 {
return false;
}
match self.0[0] {
NameComponent::Segment(_) => true,
_ => false,
}
}
pub fn normalize(self) -> Result<AmlName, AmlError> {
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)
}
NameComponent::Root => {
name.push(NameComponent::Root);
Ok(name)
}
NameComponent::Prefix => {
if let Some(NameComponent::Segment(_)) = name.iter().last() {
name.pop().unwrap();
Ok(name)
} else {
Err(AmlError::InvalidNormalizedName(self.clone()))
}
}
})?))
}
pub fn parent(&self) -> Result<AmlName, AmlError> {
let mut normalized_self = self.clone().normalize()?;
match normalized_self.0.last() {
None | Some(NameComponent::Root) => Err(AmlError::RootHasNoParent),
Some(NameComponent::Segment(_)) => {
normalized_self.0.pop();
Ok(normalized_self)
}
Some(NameComponent::Prefix) => unreachable!(), }
}
pub fn resolve(&self, scope: &AmlName) -> Result<AmlName, AmlError> {
assert!(scope.is_absolute());
if self.is_absolute() {
return Ok(self.clone());
}
let mut resolved_path = scope.clone();
resolved_path.0.extend_from_slice(&(self.0));
resolved_path.normalize()
}
}
impl fmt::Display for AmlName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_string())
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum NameComponent {
Root,
Prefix,
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::*;
use crate::test_utils::crudely_cmp_values;
#[test]
fn test_aml_name_from_str() {
assert_eq!(AmlName::from_str(""), Err(AmlError::EmptyNamesAreInvalid));
assert_eq!(AmlName::from_str("\\"), Ok(AmlName::root()));
assert_eq!(
AmlName::from_str("\\_SB.PCI0"),
Ok(AmlName(alloc::vec![
NameComponent::Root,
NameComponent::Segment(NameSeg([b'_', b'S', b'B', b'_'])),
NameComponent::Segment(NameSeg([b'P', b'C', b'I', b'0']))
]))
);
assert_eq!(
AmlName::from_str("\\_SB.^^^PCI0"),
Ok(AmlName(alloc::vec![
NameComponent::Root,
NameComponent::Segment(NameSeg([b'_', b'S', b'B', b'_'])),
NameComponent::Prefix,
NameComponent::Prefix,
NameComponent::Prefix,
NameComponent::Segment(NameSeg([b'P', b'C', b'I', b'0']))
]))
);
}
#[test]
fn test_is_normal() {
assert_eq!(AmlName::root().is_normal(), true);
assert_eq!(AmlName::from_str("\\_SB.PCI0.VGA").unwrap().is_normal(), true);
assert_eq!(AmlName::from_str("\\_SB.^PCI0.VGA").unwrap().is_normal(), false);
assert_eq!(AmlName::from_str("\\^_SB.^^PCI0.VGA").unwrap().is_normal(), false);
assert_eq!(AmlName::from_str("_SB.^^PCI0.VGA").unwrap().is_normal(), false);
assert_eq!(AmlName::from_str("_SB.PCI0.VGA").unwrap().is_normal(), true);
}
#[test]
fn test_normalization() {
assert_eq!(
AmlName::from_str("\\_SB.PCI0").unwrap().normalize(),
Ok(AmlName::from_str("\\_SB.PCI0").unwrap())
);
assert_eq!(
AmlName::from_str("\\_SB.^PCI0").unwrap().normalize(),
Ok(AmlName::from_str("\\PCI0").unwrap())
);
assert_eq!(
AmlName::from_str("\\_SB.PCI0.^^FOO").unwrap().normalize(),
Ok(AmlName::from_str("\\FOO").unwrap())
);
assert_eq!(
AmlName::from_str("_SB.PCI0.^FOO.BAR").unwrap().normalize(),
Ok(AmlName::from_str("_SB.FOO.BAR").unwrap())
);
assert_eq!(
AmlName::from_str("\\^_SB").unwrap().normalize(),
Err(AmlError::InvalidNormalizedName(AmlName::from_str("\\^_SB").unwrap()))
);
assert_eq!(
AmlName::from_str("\\_SB.PCI0.FOO.^^^^BAR").unwrap().normalize(),
Err(AmlError::InvalidNormalizedName(AmlName::from_str("\\_SB.PCI0.FOO.^^^^BAR").unwrap()))
);
}
#[test]
fn test_is_absolute() {
assert_eq!(AmlName::root().is_absolute(), true);
assert_eq!(AmlName::from_str("\\_SB.PCI0.VGA").unwrap().is_absolute(), true);
assert_eq!(AmlName::from_str("\\_SB.^PCI0.VGA").unwrap().is_absolute(), true);
assert_eq!(AmlName::from_str("\\^_SB.^^PCI0.VGA").unwrap().is_absolute(), true);
assert_eq!(AmlName::from_str("_SB.^^PCI0.VGA").unwrap().is_absolute(), false);
assert_eq!(AmlName::from_str("_SB.PCI0.VGA").unwrap().is_absolute(), false);
}
#[test]
fn test_search_rules_apply() {
assert_eq!(AmlName::root().search_rules_apply(), false);
assert_eq!(AmlName::from_str("\\_SB").unwrap().search_rules_apply(), false);
assert_eq!(AmlName::from_str("^VGA").unwrap().search_rules_apply(), false);
assert_eq!(AmlName::from_str("_SB.PCI0.VGA").unwrap().search_rules_apply(), false);
assert_eq!(AmlName::from_str("VGA").unwrap().search_rules_apply(), true);
assert_eq!(AmlName::from_str("_SB").unwrap().search_rules_apply(), true);
}
#[test]
fn test_aml_name_parent() {
assert_eq!(AmlName::from_str("\\").unwrap().parent(), Err(AmlError::RootHasNoParent));
assert_eq!(AmlName::from_str("\\_SB").unwrap().parent(), Ok(AmlName::root()));
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();
assert_eq!(namespace.add_level(AmlName::from_str("\\").unwrap(), LevelType::Scope), Ok(()));
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(()));
assert_eq!(namespace.add_level(AmlName::from_str("\\_SB.PCI0").unwrap(), LevelType::Device), Ok(()));
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(()));
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());
assert!(crudely_cmp_values(
namespace.get_by_path(&AmlName::from_str("\\MOO").unwrap()).unwrap(),
&AmlValue::Boolean(true)
));
assert!(crudely_cmp_values(
namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.A").unwrap()).unwrap(),
&AmlValue::Integer(12345)
));
assert!(crudely_cmp_values(
namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.B").unwrap()).unwrap(),
&AmlValue::Integer(6)
));
assert!(crudely_cmp_values(
namespace.get_by_path(&AmlName::from_str("\\FOO.BAR.C").unwrap()).unwrap(),
&AmlValue::String(String::from("hello, world!"))
));
{
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());
}
}
#[test]
fn test_get_level_for_path() {
let mut namespace = Namespace::new();
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(()));
{
let (_, last_seg) =
namespace.get_level_for_path(&AmlName::from_str("\\FOO.BAR.BAZ").unwrap()).unwrap();
assert_eq!(last_seg, NameSeg::from_str("BAZ").unwrap());
}
{
let (_, last_seg) = namespace.get_level_for_path(&AmlName::from_str("\\FOO").unwrap()).unwrap();
assert_eq!(last_seg, NameSeg::from_str("FOO").unwrap());
}
}
}