Skip to content

Commit 616ae44

Browse files
committed
refactor: 重构上下文管理,移除当前路径字段并添加路径计算方法
1 parent 2b05c1a commit 616ae44

File tree

4 files changed

+126
-45
lines changed

4 files changed

+126
-45
lines changed

fdt-edit/src/ctx.rs

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use alloc::{collections::BTreeMap, string::String, vec::Vec};
1+
use alloc::{
2+
collections::BTreeMap,
3+
string::{String, ToString},
4+
vec::Vec,
5+
};
26
use fdt_raw::{Phandle, Status};
37

48
use crate::{Node, RangesEntry};
@@ -13,8 +17,7 @@ pub struct Context<'a> {
1317
/// 父节点引用栈(从根节点到当前节点的父节点)
1418
/// 栈底是根节点,栈顶是当前节点的直接父节点
1519
pub parents: Vec<&'a Node>,
16-
/// 当前节点的完整路径
17-
pub current_path: String,
20+
1821
/// phandle 到节点引用的映射
1922
/// 用于通过 phandle 快速查找节点(如中断父节点)
2023
pub phandle_map: BTreeMap<Phandle, &'a Node>,
@@ -26,6 +29,14 @@ impl<'a> Context<'a> {
2629
Self::default()
2730
}
2831

32+
pub fn current_path(&self) -> String {
33+
self.parents
34+
.iter()
35+
.map(|n| n.name())
36+
.collect::<Vec<_>>()
37+
.join("/")
38+
}
39+
2940
/// 创建用于根节点的上下文
3041
pub fn for_root() -> Self {
3142
Self::default()
@@ -112,22 +123,8 @@ impl<'a> Context<'a> {
112123
parent.ranges(grandparent_address_cells)
113124
}
114125

115-
/// 添加路径段
116-
pub fn path_add(&mut self, segment: &str) {
117-
if !self.current_path.ends_with('/') {
118-
self.current_path.push('/');
119-
}
120-
self.current_path.push_str(segment);
121-
}
122-
123126
/// 压入父节点,进入子节点前调用
124127
pub fn push_parent(&mut self, parent: &'a Node) {
125-
// 更新路径
126-
if !self.current_path.ends_with('/') {
127-
self.current_path.push('/');
128-
}
129-
self.current_path.push_str(parent.name());
130-
131128
if let Some(ph) = parent.phandle() {
132129
self.phandle_map.insert(ph, parent);
133130
}
@@ -140,14 +137,6 @@ impl<'a> Context<'a> {
140137
pub fn pop_parent(&mut self) -> Option<&'a Node> {
141138
let node = self.parents.pop()?;
142139

143-
// 更新路径:移除最后一个路径段
144-
if let Some(last_slash) = self.current_path.rfind('/') {
145-
self.current_path.truncate(last_slash);
146-
if self.current_path.is_empty() {
147-
self.current_path.push('/');
148-
}
149-
}
150-
151140
Some(node)
152141
}
153142

@@ -156,7 +145,6 @@ impl<'a> Context<'a> {
156145
pub fn for_child(&self, current_node: &'a Node) -> Self {
157146
let mut child_ctx = Self {
158147
parents: self.parents.clone(),
159-
current_path: self.current_path.clone(),
160148
phandle_map: self.phandle_map.clone(),
161149
};
162150
child_ctx.push_parent(current_node);

fdt-edit/src/fdt.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,18 @@ impl Fdt {
138138
.unwrap_or_else(|| path.to_string());
139139

140140
NodeIter::new(self.root()).filter_map(move |node_ref| {
141-
let want = path.split("/");
142-
let got = node_ref.ctx.current_path.split("/");
143-
let last_idx = core::cmp::min(want.clone().count(), got.clone().count());
144-
for (w, g) in want.zip(got).take(last_idx - 1) {
145-
if w != g {
146-
return None;
147-
}
148-
}
149-
let want_name = path.rsplit('/').next().unwrap_or("");
150-
let got_name = node_ref.node.name();
151-
if !got_name.starts_with(want_name) {
152-
return None;
141+
if node_ref.path_eq_fuzzy(&path) {
142+
Some(node_ref)
143+
} else {
144+
None
153145
}
154-
Some(node_ref)
155146
})
156147
}
157148

158149
pub fn get_by_path<'a>(&'a self, path: &str) -> Option<NodeRef<'a>> {
159150
let path = self.normalize_path(path)?;
160151
NodeIter::new(self.root()).find_map(move |node_ref| {
161-
if node_ref.ctx.current_path == path {
152+
if node_ref.path_eq(&path) {
162153
Some(node_ref)
163154
} else {
164155
None
@@ -169,7 +160,7 @@ impl Fdt {
169160
pub fn get_by_path_mut<'a>(&'a mut self, path: &str) -> Option<NodeMut<'a>> {
170161
let path = self.normalize_path(path)?;
171162
NodeIterMut::new(self.root_mut()).find_map(move |node_mut| {
172-
if node_mut.ctx.current_path == path {
163+
if node_mut.path_eq(&path) {
173164
Some(node_mut)
174165
} else {
175166
None
@@ -309,7 +300,7 @@ impl Fdt {
309300

310301
// 通过 phandle 找到节点,然后构建路径
311302
if let Some(node) = self.find_by_phandle(ph) {
312-
return Ok(node.ctx.current_path.clone());
303+
return Ok(node.path());
313304
}
314305
}
315306

fdt-edit/src/node/iter.rs

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use core::{
22
fmt::Debug,
3-
ops::{Deref, DerefMut}, slice::IterMut,
3+
ops::{Deref, DerefMut},
4+
slice::IterMut,
45
};
56

6-
use alloc::vec::Vec;
7+
use alloc::{string::String, vec::Vec};
78

8-
use crate::{Context, Node, Property};
9+
use crate::{Context, Node, Property, ctx};
910

1011
#[derive(Clone, Debug)]
1112
pub enum NodeRef<'a> {
@@ -16,6 +17,25 @@ impl<'a> NodeRef<'a> {
1617
pub fn new(node: &'a Node, ctx: Context<'a>) -> Self {
1718
Self::Gerneric(NodeRefGen { node, ctx })
1819
}
20+
21+
fn op(&'a self) -> RefOp<'a> {
22+
RefOp {
23+
ctx: &self.ctx,
24+
node: self.node,
25+
}
26+
}
27+
28+
pub fn path(&self) -> String {
29+
self.op().path()
30+
}
31+
32+
pub fn path_eq(&self, path: &str) -> bool {
33+
self.op().ref_path_eq(path)
34+
}
35+
36+
pub fn path_eq_fuzzy(&self, path: &str) -> bool {
37+
self.op().ref_path_eq_fuzzy(path)
38+
}
1939
}
2040

2141
#[derive(Clone)]
@@ -67,6 +87,25 @@ impl<'a> NodeMut<'a> {
6787
pub fn new(node: &'a mut Node, ctx: Context<'a>) -> Self {
6888
Self::Gerneric(NodeMutGen { node, ctx })
6989
}
90+
91+
fn op(&'a self) -> RefOp<'a> {
92+
RefOp {
93+
ctx: &self.ctx,
94+
node: self.node,
95+
}
96+
}
97+
98+
pub fn path(&self) -> String {
99+
self.op().path()
100+
}
101+
102+
pub fn path_eq(&self, path: &str) -> bool {
103+
self.op().ref_path_eq(path)
104+
}
105+
106+
pub fn path_eq_fuzzy(&self, path: &str) -> bool {
107+
self.op().ref_path_eq_fuzzy(path)
108+
}
70109
}
71110

72111
impl<'a> Deref for NodeMut<'a> {
@@ -143,3 +182,60 @@ impl Debug for NodeRefGen<'_> {
143182
write!(f, "NodeRefGen {{ name: {} }}", self.node.name())
144183
}
145184
}
185+
186+
struct RefOp<'a> {
187+
ctx: &'a Context<'a>,
188+
node: &'a Node,
189+
}
190+
191+
impl<'a> RefOp<'a> {
192+
fn path(&self) -> String {
193+
self.ctx.current_path() + "/" + self.node.name()
194+
}
195+
196+
fn ref_path_eq(&self, path: &str) -> bool {
197+
self.path() == path
198+
}
199+
200+
fn ref_path_eq_fuzzy(&self, path: &str) -> bool {
201+
let mut want = path.trim_matches('/').split("/");
202+
let got_path = self.path();
203+
let mut got = got_path.trim_matches('/').split("/");
204+
let got_count = got.clone().count();
205+
let mut current = 0;
206+
207+
loop {
208+
let w = want.next();
209+
let g = got.next();
210+
let is_last = current + 1 == got_count;
211+
212+
match (w, g) {
213+
(Some(w), Some(g)) => {
214+
if w != g && !is_last {
215+
return false;
216+
}
217+
218+
let name = g.split('@').next().unwrap_or(g);
219+
let addr = g.split('@').nth(1);
220+
221+
let want_name = w.split('@').next().unwrap_or(w);
222+
let want_addr = w.split('@').nth(1);
223+
224+
let res = match (addr, want_addr) {
225+
(Some(a), Some(wa)) => name == want_name && a == wa,
226+
(Some(_), None) => name == want_name,
227+
(None, Some(_)) => false,
228+
(None, None) => name == want_name,
229+
};
230+
if !res {
231+
return false;
232+
}
233+
}
234+
(None, _) => break,
235+
_ => return false,
236+
}
237+
current += 1;
238+
}
239+
true
240+
}
241+
}

fdt-edit/tests/find2.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ mod tests {
2525
for n in node {
2626
println!("Found node {n:#?}");
2727
}
28+
29+
let count = fdt.find_by_path("/virtio_mmio").count();
30+
println!("Total found nodes: {}", count);
31+
assert_eq!(count, 32);
2832
}
2933

3034
#[test]
@@ -35,6 +39,8 @@ mod tests {
3539

3640
for node in fdt.all_nodes() {
3741
println!("Node: {:#?}", node);
42+
println!(" {}", node.path());
43+
println!("-------------------------");
3844
}
3945

4046
let count = fdt.all_nodes().count();

0 commit comments

Comments
 (0)