use alloc::borrow::ToOwned;
use alloc::string::{String, ToString};
use indexmap::IndexMap;
use twox_hash::xxhash64;
use super::property::DeviceTreeProperty;
use crate::error::ModelError;
use crate::{Node, Property};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeviceTreeNode {
name: String,
pub(super) properties: IndexMap<String, DeviceTreeProperty, xxhash64::State>,
pub(super) children: IndexMap<String, DeviceTreeNode, xxhash64::State>,
}
impl Default for DeviceTreeNode {
fn default() -> Self {
Self {
name: String::new(),
properties: IndexMap::with_hasher(default_hash_state()),
children: IndexMap::with_hasher(default_hash_state()),
}
}
}
impl<'a> Node<'a> for &'a DeviceTreeNode {
type Property = &'a DeviceTreeProperty;
fn name(&self) -> &'a str {
&self.name
}
fn property(&self, name: &str) -> Option<&'a DeviceTreeProperty> {
self.properties.get(name)
}
fn properties(&self) -> impl Iterator<Item = &'a DeviceTreeProperty> + use<'a> {
self.properties.values()
}
fn child(&self, name: &str) -> Option<Self> {
if name.contains('@') {
self.children.get(name)
} else {
self.children()
.find(|child| child.name_without_address() == name)
}
}
fn children(&self) -> impl Iterator<Item = Self> + use<'a> {
self.children.values()
}
}
impl DeviceTreeNode {
pub fn new(name: impl Into<String>) -> Result<Self, ModelError> {
let name = name.into();
if !crate::validate::is_valid_node_name(&name) {
return Err(ModelError::InvalidNodeName(name));
}
Ok(Self::new_unchecked(name))
}
#[must_use]
pub fn new_unchecked(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn builder(name: impl Into<String>) -> Result<DeviceTreeNodeBuilder, ModelError> {
DeviceTreeNodeBuilder::new(name)
}
pub fn properties_mut(&mut self) -> impl Iterator<Item = &mut DeviceTreeProperty> {
self.properties.values_mut()
}
#[must_use]
pub fn property_mut(&mut self, name: &str) -> Option<&mut DeviceTreeProperty> {
self.properties.get_mut(name)
}
pub fn add_property(&mut self, property: DeviceTreeProperty) {
self.properties
.insert((&property).name().to_owned(), property);
}
pub fn remove_property(&mut self, name: &str) -> Option<DeviceTreeProperty> {
self.properties.shift_remove(name)
}
pub fn children_mut(&mut self) -> impl Iterator<Item = &mut DeviceTreeNode> {
self.children.values_mut()
}
#[must_use]
pub fn child_mut(&mut self, name: &str) -> Option<&mut DeviceTreeNode> {
self.children.get_mut(name)
}
pub fn add_child(&mut self, child: DeviceTreeNode) {
self.children.insert(child.name.clone(), child);
}
pub fn remove_child(&mut self, name: &str) -> Option<DeviceTreeNode> {
self.children.shift_remove(name)
}
}
impl<'a, T: Node<'a>> From<T> for DeviceTreeNode {
fn from(node: T) -> Self {
let name = node.name().to_string();
let mut properties = IndexMap::with_hasher(default_hash_state());
properties.extend(
node.properties()
.map(|prop| (prop.name().to_owned(), prop.into())),
);
let mut children = IndexMap::with_hasher(default_hash_state());
children.extend(
node.children()
.map(|child| (child.name().to_owned(), child.into())),
);
Self {
name,
properties,
children,
}
}
}
#[derive(Debug, Default)]
pub struct DeviceTreeNodeBuilder {
node: DeviceTreeNode,
}
impl DeviceTreeNodeBuilder {
fn new(name: impl Into<String>) -> Result<Self, ModelError> {
Ok(Self {
node: DeviceTreeNode::new(name)?,
})
}
#[must_use]
pub fn property(mut self, property: DeviceTreeProperty) -> Self {
self.node.add_property(property);
self
}
#[must_use]
pub fn child(mut self, child: DeviceTreeNode) -> Self {
self.node.add_child(child);
self
}
#[must_use]
pub fn build(self) -> DeviceTreeNode {
self.node
}
}
fn default_hash_state() -> xxhash64::State {
xxhash64::State::with_seed(0xC001_C0DE)
}