use alloc::borrow::ToOwned;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use indexmap::IndexMap;
use twox_hash::xxhash64;
use super::property::DeviceTreeProperty;
use crate::error::FdtParseError;
use crate::fdt::FdtNode;
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 {
#[must_use]
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
#[must_use]
pub fn builder(name: impl Into<String>) -> DeviceTreeNodeBuilder {
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> TryFrom<FdtNode<'a>> for DeviceTreeNode {
type Error = FdtParseError;
fn try_from(node: FdtNode<'a>) -> Result<Self, Self::Error> {
let name = node.name().to_string();
let properties = node
.properties()
.map(TryInto::try_into)
.collect::<Result<Vec<DeviceTreeProperty>, _>>()?;
let mut property_map =
IndexMap::with_capacity_and_hasher(properties.len(), default_hash_state());
for property in properties {
property_map.insert((&property).name().to_owned(), property);
}
let children_vec: Vec<DeviceTreeNode> = node
.children()
.map(TryInto::try_into)
.collect::<Result<Vec<_>, _>>()?;
let mut children =
IndexMap::with_capacity_and_hasher(children_vec.len(), default_hash_state());
for child in children_vec {
children.insert(child.name.clone(), child);
}
Ok(DeviceTreeNode {
name,
properties: property_map,
children,
})
}
}
#[derive(Debug, Default)]
pub struct DeviceTreeNodeBuilder {
node: DeviceTreeNode,
}
impl DeviceTreeNodeBuilder {
fn new(name: impl Into<String>) -> Self {
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)
}