Skip to content

Commit dcc7806

Browse files
committed
feat(ser): add probe length
feat(ser): now to dtb will return total size Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
1 parent 4710a0c commit dcc7806

File tree

5 files changed

+145
-47
lines changed

5 files changed

+145
-47
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ serde = { version = "1.0", default-features = false, features = ["derive"] }
1818
dyn_serde = { version = "=1.1.2", default-features = false, optional = true }
1919

2020
[features]
21-
default = ["std", "ser"]
21+
default = ["std", "ser", "alloc"]
2222

2323
ser = ["dep:dyn_serde"]
2424
std = ["serde/std"]

src/de.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,6 @@ mod tests {
518518
use alloc::format;
519519
#[cfg(any(feature = "std", feature = "alloc"))]
520520
use serde::Deserialize;
521-
#[cfg(feature = "std")]
522-
use std::format;
523521

524522
#[cfg(any(feature = "std", feature = "alloc"))]
525523
#[test]

src/ser/mod.rs

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod patch;
22
pub mod pointer;
33
pub mod serializer;
4+
45
pub mod string_block;
56

67
use crate::common::*;
@@ -10,13 +11,17 @@ use crate::ser::patch::Patch;
1011
const RSVMAP_LEN: usize = 16;
1112

1213
/// Make dtb header with structure block and string block length.
13-
fn make_header<'se>(writer: &'se mut [u8], structure_length: u32, string_block_length: u32) {
14+
fn make_header<'se>(
15+
writer: &'se mut [u8],
16+
structure_length: u32,
17+
string_block_length: u32,
18+
) -> usize {
1419
let (header, _) = writer.split_at_mut(HEADER_LEN as usize);
1520
let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) };
21+
let total_size =
22+
HEADER_PADDING_LEN + RSVMAP_LEN as u32 + structure_length + string_block_length;
1623
header.magic = u32::from_be(DEVICE_TREE_MAGIC);
17-
header.total_size = u32::from_be(
18-
HEADER_PADDING_LEN + RSVMAP_LEN as u32 + structure_length + string_block_length,
19-
);
24+
header.total_size = u32::from_be(total_size);
2025
assert_eq!(header.total_size % 8, 0);
2126
header.off_dt_struct = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32);
2227
header.off_dt_strings = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32 + structure_length);
@@ -26,61 +31,64 @@ fn make_header<'se>(writer: &'se mut [u8], structure_length: u32, string_block_l
2631
header.boot_cpuid_phys = 0; // TODO
2732
header.size_dt_strings = u32::from_be(string_block_length as u32);
2833
header.size_dt_struct = u32::from_be(structure_length as u32);
34+
35+
total_size as usize
2936
}
3037

3138
/// Serialize the data to dtb, with a list fof Patch, write to the `writer`.
3239
///
3340
/// We do run-twice on convert, first time to generate string block, second time todo real
3441
/// structure.
35-
pub fn to_dtb<'se, T>(data: &T, list: &'se [Patch<'se>], writer: &'se mut [u8]) -> Result<(), Error>
42+
pub fn to_dtb<'se, T>(
43+
data: &T,
44+
list: &'se [Patch<'se>],
45+
writer: &'se mut [u8],
46+
) -> Result<usize, Error>
3647
where
3748
T: serde::ser::Serialize,
3849
{
3950
writer.iter_mut().for_each(|x| *x = 0);
4051

4152
let string_block_length = {
4253
let mut offset: usize = 0;
54+
let mut block = crate::ser::string_block::StringBlock::new(Some(writer), &mut offset);
55+
let mut dst = crate::ser::pointer::Pointer::new(None);
56+
let mut patch_list = crate::ser::patch::PatchList::new(list);
57+
let mut ser =
58+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
59+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
60+
data.serialize(ser)?;
4361
{
44-
let mut dst = crate::ser::pointer::Pointer::new(None);
45-
let mut patch_list = crate::ser::patch::PatchList::new(list);
46-
let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset);
47-
let mut ser =
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-
offset
52-
};
53-
{
54-
let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset);
62+
let mut block = crate::ser::string_block::StringBlock::new(Some(writer), &mut offset);
5563
block.align();
5664
};
5765
offset
5866
};
5967

6068
list.iter().for_each(|patch| patch.init());
6169
let bottom_string_block_start = writer.len() - string_block_length;
62-
// Write to bottom, avoid overlap.
63-
unsafe {
64-
core::ptr::copy(
65-
core::ptr::addr_of!(writer[0]),
66-
core::ptr::addr_of_mut!(writer[bottom_string_block_start]),
67-
string_block_length,
68-
);
69-
}
70+
71+
// Clear string block
7072
writer[0..string_block_length].fill(0);
7173

7274
let structure_length = {
7375
let (data_block, string_block) = writer.split_at_mut(writer.len() - string_block_length);
7476
let (_, data_block) = data_block.split_at_mut(HEADER_PADDING_LEN as usize + RSVMAP_LEN);
7577

7678
let mut patch_list = crate::ser::patch::PatchList::new(list);
77-
let mut temp_length = string_block_length;
78-
let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut temp_length);
79+
let mut temp_length = 0;
80+
let mut block =
81+
crate::ser::string_block::StringBlock::new(Some(string_block), &mut temp_length);
7982
let mut dst = crate::ser::pointer::Pointer::new(Some(data_block));
8083
let mut ser =
8184
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
8285
let ser = crate::ser::serializer::Serializer::new(&mut ser);
8386
let struct_len = data.serialize(ser)?.1;
87+
{
88+
let mut block =
89+
crate::ser::string_block::StringBlock::new(Some(writer), &mut temp_length);
90+
block.align();
91+
};
8492
assert_eq!(struct_len % 4, 0); // As spec, structure block align with 4 bytes.
8593
assert_eq!(temp_length, string_block_length); // StringBlock should be same with first run.
8694
struct_len
@@ -97,9 +105,32 @@ where
97105
}
98106
writer[bottom_string_block_start..].fill(0);
99107

100-
make_header(writer, structure_length as u32, string_block_length as u32);
108+
let result = make_header(writer, structure_length as u32, string_block_length as u32);
109+
110+
Ok(result)
111+
}
112+
113+
#[cfg(feature = "alloc")]
114+
pub fn probe_dtb_length<'se, T>(data: &T, list: &'se [Patch<'se>]) -> Result<usize, Error>
115+
where
116+
T: serde::ser::Serialize,
117+
{
118+
let mut offset: usize = 0;
119+
let structure_length = {
120+
let mut dst = crate::ser::pointer::Pointer::new(None);
121+
let mut patch_list = crate::ser::patch::PatchList::new(list);
122+
let mut block = crate::ser::string_block::StringBlock::new(None, &mut offset);
123+
let mut ser =
124+
crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list);
125+
let ser = crate::ser::serializer::Serializer::new(&mut ser);
126+
data.serialize(ser)?.1
127+
};
128+
{
129+
let mut block = crate::ser::string_block::StringBlock::new(None, &mut offset);
130+
block.align();
131+
};
101132

102-
Ok(())
133+
Ok(structure_length + offset + HEADER_PADDING_LEN as usize + RSVMAP_LEN)
103134
}
104135

105136
#[derive(Debug)]

src/ser/serializer.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,4 +763,39 @@ mod tests {
763763
// println!("{:x?}", buf1);
764764
// assert!(false);
765765
}
766+
#[test]
767+
#[cfg(feature = "alloc")]
768+
fn probe_length() {
769+
#[derive(Serialize)]
770+
struct Base {
771+
pub hello: u32,
772+
pub base1: Base1,
773+
pub hello2: u32,
774+
pub base2: Base1,
775+
}
776+
#[derive(Serialize)]
777+
struct Base1 {
778+
pub hello: &'static str,
779+
}
780+
let mut buf1 = [0u8; MAX_SIZE];
781+
782+
let new_base = Base1 { hello: "added" };
783+
let patch = crate::ser::patch::Patch::new(
784+
"/base3",
785+
&new_base as _,
786+
crate::ser::serializer::ValueType::Node,
787+
);
788+
let list = [patch];
789+
let base = Base {
790+
hello: 0xdeedbeef,
791+
base1: Base1 {
792+
hello: "Hello, World!",
793+
},
794+
hello2: 0x11223344,
795+
base2: Base1 { hello: "Roger" },
796+
};
797+
let probe_legnth = crate::ser::probe_dtb_length(&base, &list).unwrap();
798+
let result = crate::ser::to_dtb(&base, &list, &mut buf1).unwrap();
799+
assert_eq!(probe_legnth, result);
800+
}
766801
}

src/ser/string_block.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1+
#[cfg(feature = "alloc")]
2+
use alloc::collections::BTreeMap;
3+
14
/// StringBlock
25
/// As spec said, dtb have a block called string block for saving prop names.
36
pub struct StringBlock<'se> {
47
end: &'se mut usize,
5-
data: &'se mut [u8],
8+
data: Option<&'se mut [u8]>,
9+
#[cfg(feature = "alloc")]
10+
tree: BTreeMap<&'se str, usize>,
611
}
712

813
impl<'se> StringBlock<'se> {
914
/// Make a new string block.
1015
///
1116
/// For get how long is string block, we make `end` as a mut ref.
1217
#[inline(always)]
13-
pub fn new(dst: &'se mut [u8], end: &'se mut usize) -> StringBlock<'se> {
14-
StringBlock { data: dst, end }
18+
pub fn new(dst: Option<&'se mut [u8]>, end: &'se mut usize) -> StringBlock<'se> {
19+
StringBlock {
20+
data: dst,
21+
#[cfg(feature = "alloc")]
22+
tree: BTreeMap::new(),
23+
end,
24+
}
1525
}
1626

1727
// TODO: show as error
@@ -24,26 +34,39 @@ impl<'se> StringBlock<'se> {
2434
if offset > *self.end {
2535
panic!("invalid read");
2636
}
27-
let current_slice = &self.data[offset..];
28-
let pos = current_slice
29-
.iter()
30-
.position(|&x| x == b'\0')
31-
.unwrap_or(self.data.len());
32-
let (a, _) = current_slice.split_at(pos + 1);
33-
let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) };
34-
(result, pos + offset + 1)
37+
if let Some(data) = &self.data {
38+
let current_slice = &data[offset..];
39+
let pos = current_slice
40+
.iter()
41+
.position(|&x| x == b'\0')
42+
.unwrap_or(data.len());
43+
let (a, _) = current_slice.split_at(pos + 1);
44+
let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) };
45+
(result, pos + offset + 1)
46+
} else {
47+
panic!("must have writer when no alloc");
48+
}
49+
}
50+
51+
#[inline(always)]
52+
fn write_u8(&mut self, index: usize, data: u8) {
53+
if let Some(buffer) = &mut self.data {
54+
buffer[index] = data;
55+
}
3556
}
3657

3758
#[inline(always)]
3859
fn insert_u8(&mut self, data: u8) {
39-
self.data[*self.end] = data;
60+
self.write_u8(*self.end, data);
4061
*self.end += 1;
4162
}
4263

4364
/// Return the start offset of inserted string.
4465
#[inline(always)]
45-
pub fn insert_str(&mut self, name: &str) -> usize {
66+
pub fn insert_str(&mut self, name: &'se str) -> usize {
4667
let result = *self.end;
68+
#[cfg(feature = "alloc")]
69+
self.tree.insert(name, result);
4770
name.bytes().for_each(|x| {
4871
self.insert_u8(x);
4972
});
@@ -55,14 +78,14 @@ impl<'se> StringBlock<'se> {
5578
#[inline(always)]
5679
pub fn align(&mut self) {
5780
while (*self.end & 0b111) != 0 {
58-
self.data[*self.end] = 0;
59-
*self.end += 1;
81+
self.insert_u8(0);
6082
}
6183
}
6284

6385
/// Find a string. If not found, insert it.
6486
#[inline(always)]
65-
pub fn find_or_insert(&mut self, name: &str) -> usize {
87+
#[cfg(not(feature = "alloc"))]
88+
pub fn find_or_insert(&mut self, name: &'se str) -> usize {
6689
let mut current_pos = 0;
6790
while current_pos < *self.end {
6891
let (result, new_pos) = self.get_str_by_offset(current_pos);
@@ -74,4 +97,15 @@ impl<'se> StringBlock<'se> {
7497

7598
self.insert_str(name)
7699
}
100+
101+
#[inline(always)]
102+
#[cfg(feature = "alloc")]
103+
pub fn find_or_insert(&mut self, name: &'se str) -> usize {
104+
let result = self.tree.get(name);
105+
if result.is_some() {
106+
*result.unwrap()
107+
} else {
108+
self.insert_str(name)
109+
}
110+
}
77111
}

0 commit comments

Comments
 (0)