use core::fmt::{Debug, Display};
use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
use fdt_raw::{Phandle, Status};
use crate::{NodeId, Property, RangesEntry};
pub(crate) mod view;
#[derive(Clone)]
pub struct Node {
pub name: String,
properties: Vec<Property>,
prop_cache: BTreeMap<String, usize>,
children: Vec<NodeId>,
name_cache: BTreeMap<String, usize>,
}
impl Node {
pub fn new(name: &str) -> Self {
Self {
name: name.into(),
properties: Vec::new(),
prop_cache: BTreeMap::new(),
children: Vec::new(),
name_cache: BTreeMap::new(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn properties(&self) -> &[Property] {
&self.properties
}
pub fn children(&self) -> &[NodeId] {
&self.children
}
pub fn add_child(&mut self, name: &str, id: NodeId) {
let index = self.children.len();
self.name_cache.insert(name.into(), index);
self.children.push(id);
}
pub fn add_property(&mut self, prop: Property) {
let name = prop.name.clone();
let index = self.properties.len();
self.prop_cache.insert(name, index);
self.properties.push(prop);
}
pub fn get_child(&self, name: &str) -> Option<NodeId> {
self.name_cache
.get(name)
.and_then(|&idx| self.children.get(idx).copied())
}
pub fn remove_child(&mut self, name: &str) -> Option<NodeId> {
let &idx = self.name_cache.get(name)?;
if idx >= self.children.len() {
return None;
}
let removed = self.children.remove(idx);
self.rebuild_name_cache_from(name);
Some(removed)
}
pub(crate) fn rebuild_name_cache_from(&mut self, _removed_name: &str) {
self.name_cache.remove(_removed_name);
self.name_cache.clear();
}
pub(crate) fn rebuild_name_cache_with_names(&mut self, names: &[(String, usize)]) {
self.name_cache.clear();
for (name, idx) in names {
self.name_cache.insert(name.clone(), *idx);
}
}
pub fn set_property(&mut self, prop: Property) {
let name = prop.name.clone();
if let Some(&idx) = self.prop_cache.get(&name) {
self.properties[idx] = prop;
} else {
let idx = self.properties.len();
self.prop_cache.insert(name, idx);
self.properties.push(prop);
}
}
pub fn get_property(&self, name: &str) -> Option<&Property> {
self.prop_cache.get(name).map(|&idx| &self.properties[idx])
}
pub fn get_property_mut(&mut self, name: &str) -> Option<&mut Property> {
self.prop_cache
.get(name)
.map(|&idx| &mut self.properties[idx])
}
fn rebuild_prop_cache(&mut self) {
self.prop_cache.clear();
for (idx, prop) in self.properties.iter().enumerate() {
self.prop_cache.insert(prop.name.clone(), idx);
}
}
pub fn remove_property(&mut self, name: &str) -> Option<Property> {
if let Some(&idx) = self.prop_cache.get(name) {
let prop = self.properties.remove(idx);
self.rebuild_prop_cache();
Some(prop)
} else {
None
}
}
pub fn address_cells(&self) -> Option<u32> {
self.get_property("#address-cells")
.and_then(|prop| prop.get_u32())
}
pub fn size_cells(&self) -> Option<u32> {
self.get_property("#size-cells")
.and_then(|prop| prop.get_u32())
}
pub fn phandle(&self) -> Option<Phandle> {
self.get_property("phandle")
.and_then(|prop| prop.get_u32())
.map(Phandle::from)
}
pub fn interrupt_parent(&self) -> Option<Phandle> {
self.get_property("interrupt-parent")
.and_then(|prop| prop.get_u32())
.map(Phandle::from)
}
pub fn status(&self) -> Option<Status> {
let prop = self.get_property("status")?;
let s = prop.as_str()?;
match s {
"okay" => Some(Status::Okay),
"disabled" => Some(Status::Disabled),
_ => None,
}
}
pub fn ranges(&self, parent_address_cells: u32) -> Option<Vec<RangesEntry>> {
let prop = self.get_property("ranges")?;
let mut entries = Vec::new();
let mut reader = prop.as_reader();
let child_address_cells = self.address_cells().unwrap_or(2) as usize;
let parent_addr_cells = parent_address_cells as usize;
let size_cells = self.size_cells().unwrap_or(1) as usize;
while let (Some(child_addr), Some(parent_addr), Some(size)) = (
reader.read_cells(child_address_cells),
reader.read_cells(parent_addr_cells),
reader.read_cells(size_cells),
) {
entries.push(RangesEntry {
child_bus_address: child_addr,
parent_bus_address: parent_addr,
length: size,
});
}
Some(entries)
}
pub fn compatible(&self) -> Option<impl Iterator<Item = &str>> {
let prop = self.get_property("compatible")?;
Some(prop.as_str_iter())
}
pub fn compatibles(&self) -> impl Iterator<Item = &str> {
self.get_property("compatible")
.map(|prop| prop.as_str_iter())
.into_iter()
.flatten()
}
pub fn device_type(&self) -> Option<&str> {
let prop = self.get_property("device_type")?;
prop.as_str()
}
pub fn is_memory(&self) -> bool {
if let Some(dt) = self.device_type()
&& dt == "memory"
{
return true;
}
self.name.starts_with("memory")
}
pub fn is_interrupt_controller(&self) -> bool {
self.name.starts_with("interrupt-controller")
|| self.get_property("interrupt-controller").is_some()
}
pub fn interrupt_cells(&self) -> Option<u32> {
self.get_property("#interrupt-cells")
.and_then(|prop| prop.get_u32())
}
pub fn is_clock(&self) -> bool {
self.get_property("#clock-cells").is_some()
}
pub fn is_pci(&self) -> bool {
self.device_type() == Some("pci")
}
}
impl From<&fdt_raw::Node<'_>> for Node {
fn from(raw: &fdt_raw::Node<'_>) -> Self {
let mut new_node = Node::new(raw.name());
for raw_prop in raw.properties() {
let prop = Property::from(&raw_prop);
new_node.set_property(prop);
}
new_node
}
}
impl Display for Node {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Node(name: {})", self.name)
}
}
impl Debug for Node {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Node {{ name: {}, properties: {}, children: {} }}",
self.name,
self.properties.len(),
self.children.len()
)
}
}