Skip to content

feat: init serialize support #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Cargo.lock

# Visual Studio Code configuration files
.vscode/
*.dts
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ description = "A Device Tree blob serialization file format"
readme = "README.md"
keywords = ["serde", "serialization"]
categories = ["no-std", "encoding"]
edition = "2021"
edition = "2024"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0", default-features = false }
erased-serde = "0.4"

[dev-dependencies]
serde_derive = "1.0"
Expand Down
3 changes: 2 additions & 1 deletion examples/qemu-virt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use serde_derive::Deserialize;
// - `NodeSeq`: name@... 区分的一组同级同类的连续节点,这个类型要求可变的内存。
// - `StrSeq`: '\0' 分隔的一组字符串,设备树中一种常见的属性类型,这个类型要求可变的内存。
use serde_device_tree::{
Dtb, DtbPtr,
buildin::{Node, NodeSeq, Reg, StrSeq},
error::Error,
from_raw_mut, Dtb, DtbPtr,
from_raw_mut,
};

const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb");
Expand Down
30 changes: 30 additions & 0 deletions examples/re_encode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use serde_device_tree::{Dtb, DtbPtr, buildin::Node, error::Error, from_raw_mut};

use std::io::prelude::*;

const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb");
const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len();

#[repr(align(8))]
struct AlignedBuffer {
pub data: [u8; RAW_DEVICE_TREE.len()],
}

fn main() -> Result<(), Error> {
let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer {
data: [0; BUFFER_SIZE],
});
aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE);
let mut buf = [0u8; RAW_DEVICE_TREE.len() * 2];
let mut slice = aligned_data.data.to_vec();
let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?;
let dtb = Dtb::from(ptr).share();

let root: Node = from_raw_mut(&dtb).unwrap();
serde_device_tree::ser::to_dtb(&root, &[], &mut buf).unwrap();

let mut file = std::fs::File::create("gen.dtb").unwrap();
file.write_all(&buf).unwrap();

Ok(())
}
36 changes: 36 additions & 0 deletions examples/serialize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use serde_derive::Serialize;
use std::io::prelude::*;

const MAX_SIZE: usize = 256 + 32;

fn main() {
#[derive(Serialize)]
struct Base {
pub hello: u32,
pub base1: Base1,
pub hello2: u32,
pub base2: Base1,
}
#[derive(Serialize)]
struct Base1 {
pub hello: &'static str,
}
let mut buf1 = [0u8; MAX_SIZE];

{
let new_base = Base1 { hello: "added" };
let patch = serde_device_tree::ser::patch::Patch::new("/base3", &new_base as _);
let list = [patch];
let base = Base {
hello: 0xdeedbeef,
base1: Base1 {
hello: "Hello, World!",
},
hello2: 0x11223344,
base2: Base1 { hello: "Roger" },
};
serde_device_tree::ser::to_dtb(&base, &list, &mut buf1).unwrap();
}
let mut file = std::fs::File::create("gen.dtb").unwrap();
file.write_all(&buf1).unwrap();
}
4 changes: 4 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Use rustfmt to format code

edition = "2024"
# Empty file.
2 changes: 1 addition & 1 deletion src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) struct Header {
pub size_dt_struct: u32,
}

const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED;
pub const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED;
const U32_LEN: u32 = core::mem::size_of::<u32>() as _;

pub(crate) const ALIGN: usize = core::mem::align_of::<usize>();
Expand Down
36 changes: 19 additions & 17 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,25 @@ pub unsafe fn from_raw<'de, T>(ptr: *const u8) -> Result<T>
where
T: de::Deserialize<'de>,
{
// read header
if (ptr as usize) & (ALIGN - 1) != 0 {
return Err(Error::unaligned(ptr as usize));
}
let header = &*(ptr as *const Header);
header.verify()?;

let total_size = u32::from_be(header.total_size);
let raw_data_len = (total_size - HEADER_LEN) as usize;
let ans_ptr = core::ptr::from_raw_parts(ptr, raw_data_len);
let device_tree: &DeviceTree = &*ans_ptr;
let tags = device_tree.tags();
let mut d = Deserializer {
tags: tags.peekable(),
};
let ret = T::deserialize(&mut d)?;
Ok(ret)
unsafe {
// read header
if (ptr as usize) & (ALIGN - 1) != 0 {
return Err(Error::unaligned(ptr as usize));
}
let header = &*(ptr as *const Header);
header.verify()?;

let total_size = u32::from_be(header.total_size);
let raw_data_len = (total_size - HEADER_LEN) as usize;
let ans_ptr = core::ptr::from_raw_parts(ptr, raw_data_len);
let device_tree: &DeviceTree = &*ans_ptr;
let tags = device_tree.tags();
let mut d = Deserializer {
tags: tags.peekable(),
};
let ret = T::deserialize(&mut d)?;
Ok(ret)
}
}

#[derive(Debug)]
Expand Down
16 changes: 9 additions & 7 deletions src/de_mut/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{DtError, RefDtb, StructureBlock, BLOCK_LEN};
use super::{BLOCK_LEN, DtError, RefDtb, StructureBlock};
use core::marker::PhantomData;

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -29,10 +29,10 @@ pub enum MoveResult {
}

#[derive(Clone, Copy, Debug)]
pub(super) struct MultiNodeCursor {
pub(crate) struct MultiNodeCursor {
pub start_cursor: BodyCursor,
pub next_cursor: BodyCursor,
pub skip_cursor: BodyCursor,
pub data_cursor: BodyCursor,
#[allow(unused)]
pub node_count: u32,
}
Expand All @@ -51,6 +51,7 @@ impl<T: Type> AnyCursor<T> {

impl BodyCursor {
pub const ROOT: Self = Self(2, PhantomData);
pub const STARTER: Self = Self(0, PhantomData);

/// 移动到下一个项目。
pub fn move_on(&mut self, dtb: RefDtb) -> Cursor {
Expand Down Expand Up @@ -82,6 +83,7 @@ impl BodyCursor {
}
todo!()
}

/// 移动指针至下一块
pub fn move_next(&mut self, dtb: RefDtb) -> MoveResult {
use StructureBlock as B;
Expand Down Expand Up @@ -183,8 +185,8 @@ impl TitleCursor {
}
MultiNodeCursor {
start_cursor: group,
next_cursor: body,
skip_cursor: title_body,
skip_cursor: body,
data_cursor: title_body,
node_count: len,
}
}
Expand All @@ -201,8 +203,8 @@ impl TitleCursor {
body.escape_from(dtb);
MultiNodeCursor {
start_cursor: origin,
next_cursor: body,
skip_cursor: node,
skip_cursor: body,
data_cursor: node,
node_count: 1,
}
}
Expand Down
16 changes: 10 additions & 6 deletions src/de_mut/data.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use super::cursor::MultiNodeCursor;
use super::cursor::MultiNodeCursor;
use super::{BodyCursor, Cursor};
use super::{DtError, PropCursor, RefDtb, RegConfig};

use core::marker::PhantomData;
use serde::{de, Deserialize};
use serde::{Deserialize, de};

#[derive(Clone, Copy, Debug)]
pub(super) enum ValueCursor {
Body(BodyCursor),
Prop(BodyCursor, PropCursor),
Node(MultiNodeCursor),
NodeIn(MultiNodeCursor),
}

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -208,8 +209,9 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
visitor.visit_some(self)
}
}
ValueCursor::Node(_) => visitor.visit_some(self),
ValueCursor::NodeIn(_) => visitor.visit_some(self),
ValueCursor::Body(_) => visitor.visit_some(self),
ValueCursor::Node(_) => unreachable!("Node to option(NodeIn instead)"),
}
}

Expand Down Expand Up @@ -251,7 +253,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
{
use super::{StructAccess, StructAccessType, Temp};
match self.cursor {
ValueCursor::Node(result) => {
ValueCursor::NodeIn(result) => {
let mut start_cursor = result.start_cursor;
match start_cursor.move_on(self.dtb) {
Cursor::Title(c) => {
Expand Down Expand Up @@ -302,7 +304,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
{
use super::{StructAccess, StructAccessType, Temp};
match self.cursor {
ValueCursor::Node(_) => visitor.visit_map(StructAccess {
ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess {
access_type: StructAccessType::Map(false),
temp: Temp::Uninit,
de: self,
Expand All @@ -313,6 +315,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
de: self,
}),
ValueCursor::Prop(_, _) => unreachable!("Prop -> map"),
ValueCursor::Node(_) => unreachable!("Node -> map (Use NodeIn instead)"),
}
}

Expand All @@ -327,7 +330,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
{
use super::{StructAccess, StructAccessType, Temp};
match self.cursor {
ValueCursor::Node(_) => visitor.visit_map(StructAccess {
ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess {
access_type: StructAccessType::Struct(fields),
temp: Temp::Uninit,
de: self,
Expand All @@ -338,6 +341,7 @@ impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> {
de: self,
}),
ValueCursor::Prop(_, _) => unreachable!("Prop -> struct {_name}"),
ValueCursor::Node(_) => unreachable!("Node -> struct {_name} (Use NodeIn instead)"),
}
}

Expand Down
18 changes: 13 additions & 5 deletions src/de_mut/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Deserialize device tree data to a Rust data structure,
//! Deserialize device tree data to a Rust data structure,
//! the memory region contains dtb file should be mutable.

use crate::error::Error as DtError;
Expand All @@ -7,7 +7,7 @@
mod cursor;
mod data;
// mod group;
mod node;
pub(crate) mod node;
mod node_seq;
mod reg;
mod str_seq;
Expand All @@ -16,17 +16,20 @@
mod structs;

const VALUE_DESERIALIZER_NAME: &str = "$serde_device_tree$de_mut$ValueDeserializer";
pub(crate) const NODE_NAME: &str = "$serde_device_tree$de_mut$Node";
pub(crate) const NODE_NODE_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$NodeItem";
pub(crate) const NODE_PROP_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$PropItem";

Check warning on line 21 in src/de_mut/mod.rs

View workflow job for this annotation

GitHub Actions / Test

constant `NODE_PROP_ITEM_NAME` is never used

pub use structs::{Dtb, DtbPtr};
pub mod buildin {
pub use super::{node::Node, node_seq::NodeSeq, reg::Reg, str_seq::StrSeq};
}

use cursor::{BodyCursor, Cursor, PropCursor};
use cursor::{BodyCursor, Cursor, MultiNodeCursor, PropCursor};
use data::{ValueCursor, ValueDeserializer};
use reg::RegConfig;
use struct_access::{StructAccess, StructAccessType, Temp};
use structs::{RefDtb, StructureBlock, BLOCK_LEN};
use structs::{BLOCK_LEN, RefDtb, StructureBlock};

/// 从 [`RefDtb`] 反序列化一个描述设备树的 `T` 类型实例。
///
Expand All @@ -41,7 +44,12 @@
let mut d = ValueDeserializer {
dtb,
reg: RegConfig::DEFAULT,
cursor: ValueCursor::Body(BodyCursor::ROOT),
cursor: ValueCursor::NodeIn(MultiNodeCursor {
start_cursor: BodyCursor::STARTER,
skip_cursor: BodyCursor::ROOT, // This item will never be used.
data_cursor: BodyCursor::ROOT,
node_count: 1,
}),
};
T::deserialize(&mut d).and_then(|t| {
// 解析必须完成
Expand Down
Loading
Loading