Skip to content

Commit 8cd80ce

Browse files
committed
feat: 更新版本号至 0.1.4,优化节点遍历和删除逻辑,增强测试用例
1 parent 51d0b0e commit 8cd80ce

File tree

5 files changed

+90
-35
lines changed

5 files changed

+90
-35
lines changed

fdt-edit/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0"
1111
name = "fdt-edit"
1212
readme = "README.md"
1313
repository = "https://github.com/drivercraft/fdt-parser"
14-
version = "0.1.3"
14+
version = "0.1.4"
1515

1616
[dependencies]
1717
enum_dispatch = "0.3.13"

fdt-edit/src/ctx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl<'a> Context<'a> {
134134
if let Some(phandle) = node.phandle() {
135135
map.insert(phandle, node);
136136
}
137-
for child in &node.children {
137+
for child in node.children() {
138138
Self::build_phandle_map_from_node(child, map);
139139
}
140140
}

fdt-edit/src/fdt.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl Fdt {
124124
}
125125

126126
// 递归处理子节点
127-
for child in &node.children {
127+
for child in node.children() {
128128
let child_name = child.name();
129129
let child_path = if current_path == "/" {
130130
format!("/{}", child_name)
@@ -211,7 +211,7 @@ impl Fdt {
211211
/// ```
212212
pub fn apply_overlay(&mut self, overlay: &Fdt) -> Result<(), FdtError> {
213213
// 遍历 overlay 根节点的所有子节点
214-
for child in &overlay.root.children {
214+
for child in overlay.root.children() {
215215
if child.name().starts_with("fragment@") || child.name() == "fragment" {
216216
// fragment 格式
217217
self.apply_fragment(child)?;
@@ -515,7 +515,7 @@ impl core::fmt::Debug for Fdt {
515515
.field("boot_cpuid_phys", &self.boot_cpuid_phys)
516516
.field("memory_reservations_count", &self.memory_reservations.len())
517517
.field("root_node_name", &self.root.name)
518-
.field("total_nodes", &self.root.children.len())
518+
.field("total_nodes", &self.root.children().len())
519519
.field("phandle_cache_size", &self.phandle_cache.len())
520520
.finish()
521521
}

fdt-edit/src/node/mod.rs

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ pub struct Node {
4141
pub(crate) properties: Vec<Property>,
4242
/// 属性名到索引的映射(用于快速查找)
4343
pub(crate) prop_cache: BTreeMap<String, usize>,
44-
pub(crate) children: Vec<Node>,
45-
pub(crate) name_cache: BTreeMap<String, usize>,
44+
children: Vec<Node>,
45+
name_cache: BTreeMap<String, usize>,
4646
}
4747

4848
impl Node {
@@ -64,8 +64,8 @@ impl Node {
6464
self.properties.iter()
6565
}
6666

67-
pub fn children(&self) -> impl Iterator<Item = &Node> {
68-
self.children.iter()
67+
pub fn children(&self) -> &[Node] {
68+
&self.children
6969
}
7070

7171
pub fn children_mut(&mut self) -> impl Iterator<Item = &mut Node> {
@@ -87,27 +87,41 @@ impl Node {
8787

8888
pub fn get_child(&self, name: &str) -> Option<&Node> {
8989
if let Some(&index) = self.name_cache.get(name) {
90-
self.children.get(index)
91-
} else {
92-
None
90+
if let Some(child) = self.children.get(index) {
91+
return Some(child);
92+
}
9393
}
94+
95+
// Fallback if the cache is stale
96+
self.children.iter().find(|c| c.name == name)
9497
}
9598

9699
pub fn get_child_mut(&mut self, name: &str) -> Option<&mut Node> {
97100
if let Some(&index) = self.name_cache.get(name) {
98-
self.children.get_mut(index)
99-
} else {
100-
None
101+
if index < self.children.len() && self.children[index].name == name {
102+
return self.children.get_mut(index);
103+
}
101104
}
105+
106+
// Cache miss or mismatch: search and rebuild cache to keep indices in sync
107+
let pos = self.children.iter().position(|c| c.name == name)?;
108+
self.rebuild_name_cache();
109+
self.children.get_mut(pos)
102110
}
103111

104112
pub fn remove_child(&mut self, name: &str) -> Option<Node> {
105-
if let Some(&index) = self.name_cache.get(name) {
106-
self.name_cache.remove(name);
107-
Some(self.children.remove(index))
108-
} else {
109-
None
110-
}
113+
let index = self
114+
.name_cache
115+
.get(name)
116+
.copied()
117+
.filter(|&idx| self.children.get(idx).map(|c| c.name.as_str()) == Some(name))
118+
.or_else(|| self.children.iter().position(|c| c.name == name));
119+
120+
let Some(idx) = index else { return None };
121+
122+
let removed = self.children.remove(idx);
123+
self.rebuild_name_cache();
124+
Some(removed)
111125
}
112126

113127
pub fn set_property(&mut self, prop: Property) {
@@ -208,6 +222,13 @@ impl Node {
208222
Some(entries)
209223
}
210224

225+
fn rebuild_name_cache(&mut self) {
226+
self.name_cache.clear();
227+
for (idx, child) in self.children.iter().enumerate() {
228+
self.name_cache.insert(child.name.clone(), idx);
229+
}
230+
}
231+
211232
pub fn compatible(&self) -> Option<StrIter<'_>> {
212233
let prop = self.get_property("compatible")?;
213234
Some(prop.as_str_iter())
@@ -259,11 +280,10 @@ impl Node {
259280
if parts.is_empty() {
260281
return Err(fdt_raw::FdtError::InvalidInput);
261282
}
262-
263283
if parts.len() == 1 {
264284
// 删除直接子节点(精确匹配)
265285
let child_name = parts[0];
266-
Ok(self.remove_child_exact(child_name))
286+
Ok(self.remove_child(child_name))
267287
} else {
268288
// 需要递归到父节点进行删除
269289
self.remove_child_recursive(&parts, 0)
@@ -280,7 +300,7 @@ impl Node {
280300
if index >= parts.len() - 1 {
281301
// 已经到达要删除节点的父级
282302
let child_name_to_remove = parts[index];
283-
Ok(self.remove_child_exact(child_name_to_remove))
303+
Ok(self.remove_child(child_name_to_remove))
284304
} else {
285305
// 继续向下递归
286306
let current_part = parts[index];
@@ -294,17 +314,6 @@ impl Node {
294314
}
295315
}
296316
}
297-
298-
/// 精确删除子节点,不支持部分匹配
299-
fn remove_child_exact(&mut self, name: &str) -> Option<Node> {
300-
if let Some(&index) = self.name_cache.get(name) {
301-
let child = self.children.remove(index);
302-
self.name_cache.remove(name);
303-
Some(child)
304-
} else {
305-
None
306-
}
307-
}
308317
}
309318

310319
impl From<&fdt_raw::Node<'_>> for Node {

fdt-edit/tests/remove_node.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
#[cfg(test)]
22
mod tests {
3+
use std::sync::Once;
4+
35
use dtb_file::fdt_qemu;
46
use fdt_edit::*;
57

8+
fn init_logging() {
9+
static INIT: Once = Once::new();
10+
INIT.call_once(|| {
11+
let _ = env_logger::builder()
12+
.is_test(true)
13+
.filter_level(log::LevelFilter::Trace)
14+
.try_init();
15+
});
16+
}
17+
618
#[test]
719
fn test_remove_node_exact_path() {
20+
init_logging();
821
// 解析原始 DTB
922
let raw_data = fdt_qemu();
1023
let mut fdt = Fdt::from_bytes(&raw_data).unwrap();
@@ -23,6 +36,39 @@ mod tests {
2336
assert!(node_after.is_none(), "psci 节点应该已被删除");
2437
}
2538

39+
#[test]
40+
fn test_remove_node_exact_path_parts() {
41+
init_logging();
42+
// 解析原始 DTB
43+
let raw_data = fdt_qemu();
44+
let mut fdt = Fdt::from_bytes(&raw_data).unwrap();
45+
46+
let memory = fdt.find_by_path("/memory").next().unwrap();
47+
fdt.remove_node(&memory.path()).unwrap();
48+
49+
let cpus = fdt.find_by_path("/cpus/cpu").collect::<Vec<_>>();
50+
let path = cpus[0].path();
51+
println!("Removing node at path: {}", path);
52+
// drop(node);
53+
54+
// 删除节点
55+
let removed = fdt.remove_node(&path);
56+
assert!(removed.is_ok(), "删除应该成功");
57+
assert!(removed.unwrap().is_some(), "应该返回被删除的节点");
58+
59+
// 验证节点已被删除
60+
let node_after = fdt.get_by_path("/cpus/cpu@0");
61+
assert!(node_after.is_none(), "cpu 节点应该已被删除");
62+
63+
let raw = fdt.encode();
64+
let fdt2 = Fdt::from_bytes(&raw).unwrap();
65+
let node_after_reload = fdt2.get_by_path("/cpus/cpu@0");
66+
assert!(
67+
node_after_reload.is_none(),
68+
"重新加载后 cpu 节点应该已被删除"
69+
);
70+
}
71+
2672
#[test]
2773
fn test_remove_nested_node() {
2874
// 使用手动创建的树测试嵌套删除

0 commit comments

Comments
 (0)