diff --git a/src/de_mut/cursor.rs b/src/de_mut/cursor.rs index dadb5cc..d0dca23 100644 --- a/src/de_mut/cursor.rs +++ b/src/de_mut/cursor.rs @@ -28,6 +28,15 @@ pub enum MoveResult { Others, } +#[derive(Clone, Copy, Debug)] +pub(super) struct MultiNodeCursor { + pub start_cursor: BodyCursor, + pub next_cursor: BodyCursor, + pub skip_cursor: BodyCursor, + #[allow(unused)] + pub node_count: u32, +} + impl AnyCursor { /// 移动 `n` 格。 pub fn step_n(&mut self, len: usize) { @@ -147,12 +156,13 @@ impl TitleCursor { } /// 生成组光标。 - pub fn take_group_on(&self, dtb: RefDtb, name: &str) -> (BodyCursor, usize, BodyCursor) { + pub fn take_group_on(&self, dtb: RefDtb, name: &str) -> MultiNodeCursor { let name_bytes = name.as_bytes(); let name_skip = align(name_bytes.len() + 1, BLOCK_LEN); let group = AnyCursor::(self.0, PhantomData); - let mut body = AnyCursor::(self.0 + 1 + name_skip, PhantomData); + let title_body = AnyCursor::(self.0 + 1 + name_skip, PhantomData); + let mut body = title_body; let mut len = 1; let structure = &dtb.borrow().structure; @@ -171,19 +181,30 @@ impl TitleCursor { } break; } - (group, len, body) + MultiNodeCursor { + start_cursor: group, + next_cursor: body, + skip_cursor: title_body, + node_count: len, + } } /// 生成节点光标。 - pub fn take_node_on(&self, dtb: RefDtb, name: &str) -> (BodyCursor, BodyCursor) { + pub fn take_node_on(&self, dtb: RefDtb, name: &str) -> MultiNodeCursor { let name_bytes = name.as_bytes(); let name_skip = align(name_bytes.len() + 1, BLOCK_LEN); + let origin = AnyCursor::(self.0, PhantomData); let node = AnyCursor::(self.0 + 1 + name_skip, PhantomData); let mut body = AnyCursor::(self.0 + 1 + name_skip, PhantomData); body.escape_from(dtb); - (node, body) + MultiNodeCursor { + start_cursor: origin, + next_cursor: body, + skip_cursor: node, + node_count: 1, + } } } diff --git a/src/de_mut/data.rs b/src/de_mut/data.rs index 9145ccd..e4053ae 100644 --- a/src/de_mut/data.rs +++ b/src/de_mut/data.rs @@ -1,4 +1,5 @@ -use super::{BodyCursor, Cursor}; +use super::cursor::MultiNodeCursor; +use super::{BodyCursor, Cursor}; use super::{DtError, PropCursor, RefDtb, RegConfig}; use core::marker::PhantomData; @@ -6,8 +7,9 @@ use serde::{de, Deserialize}; #[derive(Clone, Copy, Debug)] pub(super) enum ValueCursor { - Prop(BodyCursor, PropCursor), Body(BodyCursor), + Prop(BodyCursor, PropCursor), + Node(MultiNodeCursor), } #[derive(Clone, Copy)] @@ -206,6 +208,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { visitor.visit_some(self) } } + ValueCursor::Node(_) => visitor.visit_some(self), ValueCursor::Body(_) => visitor.visit_some(self), } } @@ -247,25 +250,30 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { V: de::Visitor<'de>, { use super::{StructAccess, StructAccessType, Temp}; - match self.move_on() { - Cursor::Title(c) => { - let (name, _) = c.split_on(self.dtb); - let cursor = match self.cursor { - ValueCursor::Body(cursor) => cursor, - _ => unreachable!(""), - }; - - let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); - let name_bytes = &name.as_bytes()[..pre_len]; - let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; - - visitor.visit_seq(StructAccess { - access_type: StructAccessType::Seq(name), - temp: Temp::Node(cursor, cursor), - de: self, - }) + match self.cursor { + ValueCursor::Node(result) => { + let mut start_cursor = result.start_cursor; + match start_cursor.move_on(self.dtb) { + Cursor::Title(c) => { + let (name, _) = c.split_on(self.dtb); + + let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); + let name_bytes = &name.as_bytes()[..pre_len]; + let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; + + let de = self; + de.cursor = ValueCursor::Body(start_cursor); + + visitor.visit_seq(StructAccess { + access_type: StructAccessType::Seq(name), + temp: Temp::Uninit, + de, + }) + } + _ => unreachable!("seq request on a none seq cursor"), + } } - _ => unreachable!("seq request on a none seq cursor"), + _ => unreachable!("Seq request on a not-node cursor"), } } @@ -293,14 +301,19 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { V: de::Visitor<'de>, { use super::{StructAccess, StructAccessType, Temp}; - if let ValueCursor::Body(cursor) = self.cursor { - return visitor.visit_map(StructAccess { + match self.cursor { + ValueCursor::Node(_) => visitor.visit_map(StructAccess { access_type: StructAccessType::Map(false), - temp: Temp::Node(cursor, cursor), + temp: Temp::Uninit, de: self, - }); - }; - unreachable!("Prop -> map") + }), + ValueCursor::Body(_) => visitor.visit_map(StructAccess { + access_type: StructAccessType::Map(false), + temp: Temp::Uninit, + de: self, + }), + ValueCursor::Prop(_, _) => unreachable!("Prop -> map"), + } } fn deserialize_struct( @@ -313,14 +326,19 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { V: de::Visitor<'de>, { use super::{StructAccess, StructAccessType, Temp}; - if let ValueCursor::Body(cursor) = self.cursor { - return visitor.visit_map(StructAccess { + match self.cursor { + ValueCursor::Node(_) => visitor.visit_map(StructAccess { access_type: StructAccessType::Struct(fields), - temp: Temp::Node(cursor, cursor), + temp: Temp::Uninit, de: self, - }); - }; - unreachable!("Prop -> struct {_name} {fields:?}") + }), + ValueCursor::Body(_) => visitor.visit_map(StructAccess { + access_type: StructAccessType::Struct(fields), + temp: Temp::Uninit, + de: self, + }), + ValueCursor::Prop(_, _) => unreachable!("Prop -> struct {_name}"), + } } fn deserialize_enum( diff --git a/src/de_mut/node.rs b/src/de_mut/node.rs index 60667b6..2ff632f 100644 --- a/src/de_mut/node.rs +++ b/src/de_mut/node.rs @@ -124,14 +124,14 @@ impl<'de> Iterator for NodeIter<'de, '_> { let dtb = self.node.dtb; if let Cursor::Title(c) = cursor.move_on(dtb) { let (name, _) = c.split_on(dtb); - let (node_cursor, next) = c.take_node_on(dtb, name); + let node_cursor = c.take_node_on(dtb, name); let res = Some(Self::Item { dtb, reg: self.node.reg, - node: node_cursor, + node: node_cursor.skip_cursor, name, }); - *cursor = next; + *cursor = node_cursor.next_cursor; res } else { None @@ -201,7 +201,8 @@ impl<'de> Deserialize<'de> for Node<'_> { if key == "/" { self_cursor = match value.cursor { ValueCursor::Body(cursor) => Some(cursor), - ValueCursor::Prop(_, _) => { + ValueCursor::Node(result) => Some(result.next_cursor), + _ => { unreachable!("root of NodeSeq shouble be body cursor") } }; @@ -213,11 +214,12 @@ impl<'de> Deserialize<'de> for Node<'_> { props_start = Some(cursor); } } - ValueCursor::Body(cursor) => { + ValueCursor::Node(cursor) => { if nodes_start.is_none() { - nodes_start = Some(cursor); + nodes_start = Some(cursor.start_cursor); } } + _ => unreachable!("unparsed(body) cursor"), } } diff --git a/src/de_mut/node_seq.rs b/src/de_mut/node_seq.rs index bcc4808..1247803 100644 --- a/src/de_mut/node_seq.rs +++ b/src/de_mut/node_seq.rs @@ -133,19 +133,19 @@ impl<'de> Iterator for NodeSeqIter<'de, '_> { // 子节点名字 Cursor::Title(c) => { let (full_name, _) = c.split_on(self.de.dtb); - let (node, next) = c.take_node_on(self.de.dtb, full_name); + let node_reuslt = c.take_node_on(self.de.dtb, full_name); let (pre_name, suf_name) = full_name.split_once('@').unwrap_or((full_name, "")); if self.seq.name != pre_name { return None; } - self.de.cursor = ValueCursor::Body(next); + self.de.cursor = ValueCursor::Body(node_reuslt.next_cursor); Some(Self::Item { dtb: self.de.dtb, reg: self.de.reg, - body: node, + body: node_reuslt.skip_cursor, at: suf_name, }) } @@ -173,3 +173,84 @@ impl<'de> NodeSeqItem<'de> { .unwrap() } } + +#[cfg(test)] +mod tests { + use crate::buildin::{NodeSeq, Reg}; + use crate::{from_raw_mut, Dtb, DtbPtr}; + use serde_derive::Deserialize; + + const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); + const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); + const RAW_DEVICE_TREE_QEMU: &[u8] = include_bytes!("../../examples/qemu-virt.dtb"); + const BUFFER_SIZE_QEMU: usize = RAW_DEVICE_TREE_QEMU.len(); + #[derive(Deserialize)] + pub struct Tree<'a> { + /// Memory information. + pub memory: NodeSeq<'a>, + } + /// Memory range. + #[derive(Deserialize)] + #[serde(rename_all = "kebab-case")] + pub struct Memory<'a> { + pub reg: Reg<'a>, + } + #[test] + fn test_nodeseq_without_at() { + #[repr(align(8))] + struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE.len()], + } + let mut aligned_data: Box = Box::new(AlignedBuffer { + data: [0; BUFFER_SIZE], + }); + aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); + let mut slice = aligned_data.data.to_vec(); + let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); + let dtb = Dtb::from(ptr).share(); + + let t: Tree = from_raw_mut(&dtb).unwrap(); + assert_eq!(t.memory.len(), 1); + let range = t + .memory + .iter() + .next() + .unwrap() + .deserialize::() + .reg + .iter() + .next() + .unwrap() + .0; + assert_eq!(range, 1342177280..1408237568); + } + #[test] + fn test_nodeseq_with_at() { + #[repr(align(8))] + struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE_QEMU.len()], + } + let mut aligned_data: Box = Box::new(AlignedBuffer { + data: [0; BUFFER_SIZE_QEMU], + }); + aligned_data.data[..BUFFER_SIZE_QEMU].clone_from_slice(RAW_DEVICE_TREE_QEMU); + let mut slice = aligned_data.data.to_vec(); + let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); + let dtb = Dtb::from(ptr).share(); + + let t: Tree = from_raw_mut(&dtb).unwrap(); + assert_eq!(t.memory.len(), 1); + let range = t + .memory + .iter() + .next() + .unwrap() + .deserialize::() + .reg + .iter() + .next() + .unwrap() + .0; + assert_eq!(range, 2147483648..6442450944); + } +} diff --git a/src/de_mut/struct_access.rs b/src/de_mut/struct_access.rs index fdfcc82..ce2d928 100644 --- a/src/de_mut/struct_access.rs +++ b/src/de_mut/struct_access.rs @@ -1,3 +1,4 @@ +use super::cursor::MultiNodeCursor; use super::{BodyCursor, Cursor, PropCursor, ValueCursor, ValueDeserializer}; use crate::error::Error as DtError; use serde::de; @@ -21,8 +22,8 @@ pub struct StructAccess<'de, 'b> { /// 解析键(名字)时将确定值类型,保存 `Temp` 类型的状态。 /// 根据状态分发值解析器。 pub enum Temp { - Node(BodyCursor, BodyCursor), - Group(BodyCursor), + Uninit, + Nodes(MultiNodeCursor), Prop(BodyCursor, PropCursor), } @@ -46,6 +47,12 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { _ => true, } }; + let origin_cursor = match self.de.cursor { + ValueCursor::Body(cursor) => cursor, + ValueCursor::Node(result) => result.skip_cursor, + _ => unreachable!("map access's cursor should always be body cursor"), + }; + self.de.cursor = ValueCursor::Body(origin_cursor); let name = loop { let origin_cursor = match self.de.cursor { ValueCursor::Body(cursor) => cursor, @@ -59,19 +66,19 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { let (pre_name, _) = name.split_once('@').unwrap_or((name, "")); // 子节点名字不带 @ 或正在解析 Node 类型 if pre_name == name || check_contains(name) { - let (node, next) = c.take_node_on(self.de.dtb, name); - self.de.cursor = ValueCursor::Body(next); + let take_result = c.take_node_on(self.de.dtb, name); + self.de.cursor = ValueCursor::Body(take_result.next_cursor); if check_contains(name) { - self.temp = Temp::Node(origin_cursor, node); + self.temp = Temp::Nodes(take_result); break name; } } // @ 之前的部分是真正的名字,用这个名字搜索连续的一组 else { - let (group, _, next) = c.take_group_on(self.de.dtb, pre_name); - self.de.cursor = ValueCursor::Body(next); + let take_result = c.take_group_on(self.de.dtb, pre_name); + self.de.cursor = ValueCursor::Body(take_result.next_cursor); if check_contains(pre_name) { - self.temp = Temp::Group(group); + self.temp = Temp::Nodes(take_result); break pre_name; } } @@ -120,30 +127,22 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { } } match self.temp { - Temp::Node(cursor, node_cursor) => { + Temp::Nodes(ref result) => { // 键是独立节点名字,递归 match self.access_type { StructAccessType::Map(_) => seed.deserialize(&mut ValueDeserializer { dtb: self.de.dtb, reg: self.de.reg, - cursor: ValueCursor::Body(cursor), + cursor: ValueCursor::Node(*result), }), StructAccessType::Struct(_) => seed.deserialize(&mut ValueDeserializer { dtb: self.de.dtb, reg: self.de.reg, - cursor: ValueCursor::Body(node_cursor), + cursor: ValueCursor::Node(*result), }), _ => unreachable!(), } } - Temp::Group(cursor) => { - // 键是组名字,构造组反序列化器 - seed.deserialize(&mut ValueDeserializer { - dtb: self.de.dtb, - reg: self.de.reg, - cursor: ValueCursor::Body(cursor), - }) - } Temp::Prop(origin_cursor, cursor) => { // 键是属性名字,构造属性反序列化器 seed.deserialize(&mut ValueDeserializer { @@ -152,6 +151,9 @@ impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { cursor: ValueCursor::Prop(origin_cursor, cursor), }) } + Temp::Uninit => { + unreachable!("find uninited result") + } } } } @@ -168,7 +170,7 @@ impl<'de> de::SeqAccess<'de> for StructAccess<'de, '_> { // 子节点名字 Cursor::Title(c) => { let (name, _) = c.split_on(self.de.dtb); - let (_, next) = c.take_node_on(self.de.dtb, name); + let next = c.take_node_on(self.de.dtb, name).next_cursor; let prev_cursor = match self.de.cursor { ValueCursor::Body(cursor) => cursor, _ => unreachable!(), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 0e11e6e..c71c673 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -51,7 +51,7 @@ impl<'de> Node<'de> { } return None; } - return self.raw_find(path); + self.raw_find(path) } /// use depth-first search to traversal the tree, and exec func for each node diff --git a/tests/bl808.rs b/tests/bl808.rs new file mode 100644 index 0000000..3eaac1d --- /dev/null +++ b/tests/bl808.rs @@ -0,0 +1,35 @@ +// 在实际使用中,将这里的 `serde_derive::Deserialize` 改为 `serde::Deserialize`。 +use serde_derive::Deserialize; + +use serde_device_tree::{buildin::NodeSeq, error::Error, from_raw_mut, Dtb, DtbPtr}; + +const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/bl808.dtb"); +const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); + +#[repr(align(8))] +struct AlignedBuffer { + pub data: [u8; RAW_DEVICE_TREE.len()], +} + +/// Root device tree structure containing system information. +#[derive(Deserialize)] +pub struct Tree<'a> { + /// Memory information. + pub memory: NodeSeq<'a>, +} + +#[test] +fn bl808() -> Result<(), Error> { + // 整个设备树二进制文件需要装载到一块可写的内存区域 + let mut aligned_data: Box = Box::new(AlignedBuffer { + data: [0; BUFFER_SIZE], + }); + aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); + let mut slice = aligned_data.data.to_vec(); + let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; + let dtb = Dtb::from(ptr).share(); + + let _: Tree = from_raw_mut(&dtb).unwrap(); + + Ok(()) +}