Skip to content

Commit f9f177c

Browse files
committed
fix: can not add a new node / prop
refactor: serialize and patch To avoid copy-paste word, we use SerializeMap instead of `serialize_newtype_struct`. This change required rewrite `serialize_dynamic_field` function and split it, so we can not use backtracking. Now it will create a new serailizer for every node or prop. Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
1 parent 2a5d6ab commit f9f177c

File tree

7 files changed

+256
-158
lines changed

7 files changed

+256
-158
lines changed

examples/re_encode.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use serde_device_tree::ser::{patch::Patch, serializer::ValueType};
12
use serde_device_tree::{Dtb, DtbPtr, buildin::Node, error::Error, from_raw_mut};
23

34
use std::io::prelude::*;
@@ -21,7 +22,8 @@ fn main() -> Result<(), Error> {
2122
let dtb = Dtb::from(ptr).share();
2223

2324
let root: Node = from_raw_mut(&dtb).unwrap();
24-
serde_device_tree::ser::to_dtb(&root, &[], &mut buf).unwrap();
25+
let patch: Patch = Patch::new("/chosen/a", &"1", ValueType::Prop);
26+
serde_device_tree::ser::to_dtb(&root, &[patch], &mut buf).unwrap();
2527

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

examples/serialize.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use serde::Serialize;
22
use std::io::prelude::*;
33

4+
use serde_device_tree::ser::serializer::ValueType;
5+
46
const MAX_SIZE: usize = 256 + 32;
57

68
fn main() {
@@ -19,7 +21,8 @@ fn main() {
1921

2022
{
2123
let new_base = Base1 { hello: "added" };
22-
let patch = serde_device_tree::ser::patch::Patch::new("/base3", &new_base as _);
24+
let patch =
25+
serde_device_tree::ser::patch::Patch::new("/base3", &new_base as _, ValueType::Node);
2326
let list = [patch];
2427
let base = Base {
2528
hello: 0xdeedbeef,

src/de_mut/node.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ impl<'de> Node<'de> {
5757
let result = match self.cursor.clone().move_on(self.dtb) {
5858
Cursor::Title(c) => {
5959
let (name, _) = c.split_on(self.dtb);
60-
let take_result = c.take_node_on(self.dtb, name);
61-
take_result
60+
61+
c.take_node_on(self.dtb, name)
6262
}
6363
_ => unreachable!("Node's cursor should on its start"),
6464
};
@@ -333,7 +333,15 @@ impl Serialize for Node<'_> {
333333
where
334334
S: serde::Serializer,
335335
{
336-
serializer.serialize_newtype_struct(crate::de_mut::NODE_NAME, self)
336+
use serde::ser::SerializeMap;
337+
let mut map = serializer.serialize_map(None)?;
338+
for prop in self.props() {
339+
map.serialize_entry(prop.get_name(), &prop)?;
340+
}
341+
for node in self.nodes() {
342+
map.serialize_entry(node.get_full_name(), &node.deserialize::<Node>())?;
343+
}
344+
map.end()
337345
}
338346
}
339347

src/ser/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ where
2525
let mut patch_list = crate::ser::patch::PatchList::new(list);
2626
let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset);
2727
let mut ser =
28-
crate::ser::serializer::Serializer::new(&mut dst, &mut block, &mut patch_list);
29-
data.serialize(&mut ser)?;
28+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
29+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
30+
data.serialize(ser)?;
3031
};
3132
list.iter().for_each(|patch| patch.init());
3233
// Write from bottom to top, to avoid overlap.
@@ -44,11 +45,11 @@ where
4445
let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut offset);
4546
let mut dst = crate::ser::pointer::Pointer::new(Some(data_block));
4647
let mut ser =
47-
crate::ser::serializer::Serializer::new(&mut dst, &mut block, &mut patch_list);
48-
data.serialize(&mut ser)?;
49-
ser.dst.step_by_u32(FDT_END);
50-
ser.dst.get_offset()
51-
};
48+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
49+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
50+
data.serialize(ser)?
51+
}
52+
.1;
5253
// Make header
5354
{
5455
let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) };

src/ser/patch.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
11
use super::serializer::Serializer;
2+
use super::serializer::ValueType;
23
use core::cell::Cell;
34

45
/// Since this crate is mostly work with `noalloc`, we use `Patch` and `PatchList` for change or
56
/// add on a dtb.
67
pub struct Patch<'se> {
7-
pub data: &'se dyn dyn_serde::Serialize,
88
name: &'se str,
9+
pub data: &'se dyn dyn_serde::Serialize,
10+
pub patch_type: ValueType,
911

1012
/// This patch match how many item between its path and serializer.
1113
matched_depth: Cell<usize>,
1214
/// Show this patch have been parsed.
1315
parsed: Cell<bool>,
1416
}
1517

18+
impl core::fmt::Debug for Patch<'_> {
19+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20+
f.debug_struct("")
21+
.field("name", &self.name)
22+
.field("patch_type", &self.patch_type)
23+
.field("matched_depth", &self.matched_depth)
24+
.field("parsed", &self.parsed)
25+
.finish()
26+
}
27+
}
28+
1629
impl<'se> Patch<'se> {
1730
#[inline(always)]
18-
pub fn new(name: &'se str, data: &'se dyn dyn_serde::Serialize) -> Patch<'se> {
31+
pub fn new(
32+
name: &'se str,
33+
data: &'se dyn dyn_serde::Serialize,
34+
patch_type: ValueType,
35+
) -> Patch<'se> {
1936
Patch {
2037
name,
2138
data,
22-
matched_depth: Cell::new(0),
39+
patch_type,
40+
matched_depth: Cell::new(1),
2341
parsed: Cell::new(false),
2442
}
2543
}
2644

2745
#[inline(always)]
2846
/// Reset the status of patch.
2947
pub fn init(&self) {
30-
self.matched_depth.set(0);
48+
self.matched_depth.set(1);
3149
self.parsed.set(false);
3250
}
3351

@@ -38,17 +56,14 @@ impl<'se> Patch<'se> {
3856

3957
#[inline(always)]
4058
pub fn get_depth_path(&self, x: usize) -> &'se str {
41-
if x == 0 {
42-
return "";
43-
}
44-
self.name.split('/').nth(x).unwrap_or_default()
59+
self.name.split('/').nth(x - 1).unwrap_or_default()
4560
}
4661

4762
// I hope to impl serde::ser::Serializer, but erase_serialize's return value is different from
4863
// normal serialize, so we do this.
4964
/// Serialize this patch with serializer.
5065
#[inline(always)]
51-
pub fn serialize(&self, serializer: &mut Serializer<'se>) {
66+
pub fn serialize(&self, serializer: Serializer<'_, 'se>) {
5267
self.parsed.set(true);
5368
self.data
5469
.serialize_dyn(&mut <dyn dyn_serde::Serializer>::new(serializer))
@@ -57,18 +72,20 @@ impl<'se> Patch<'se> {
5772
}
5873

5974
/// Here is a list of `Patch`, and have some methods for update `Patch` status.
75+
#[derive(Debug)]
6076
pub struct PatchList<'se> {
6177
list: &'se [Patch<'se>],
6278
}
6379

6480
impl<'se> PatchList<'se> {
6581
#[inline(always)]
6682
pub fn new(list: &'se [Patch<'se>]) -> PatchList<'se> {
83+
list.iter().for_each(|x| x.init());
6784
PatchList { list }
6885
}
6986

7087
#[inline(always)]
71-
pub fn step_forward(&self, name: &'se str, depth: usize) -> Option<&'se Patch<'se>> {
88+
pub fn step_forward(&self, name: &str, depth: usize) -> Option<&'se Patch<'se>> {
7289
let mut matched_patch = None;
7390
self.list.iter().for_each(|patch| {
7491
if patch.matched_depth.get() == depth - 1 && patch.get_depth_path(depth) == name {

src/ser/pointer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ impl<'se> Pointer<'se> {
3131
}
3232
}
3333

34+
/// Create a PROP header with nop padding, return the offset of `FDT_PROP` token.
3435
#[inline(always)]
3536
pub fn step_by_prop(&mut self) -> usize {
3637
self.step_by_u32(FDT_PROP);
3738
let offset = self.offset;
39+
// Put 2 nop as `name` and `nameoff`.
3840
self.step_by_u32(FDT_NOP); // When create prop header, we do not know how long of the prop value.
3941
self.step_by_u32(FDT_NOP); // We can not assume this is a prop, so nop for default.
4042
offset

0 commit comments

Comments
 (0)