Skip to content

Commit d383382

Browse files
committed
docs: 补全文档,deny missing docs
feat: use `Str` for every string Signed-off-by: YdrMaster <[email protected]>
1 parent a3b69dc commit d383382

File tree

11 files changed

+165
-74
lines changed

11 files changed

+165
-74
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
1212

1313
## 未发布
1414

15+
## Unreleased
16+
1517
### Changed
1618

1719
- 规范化更新日志格式
20+
- 字符串统一使用一个封装的 `Str` 类型(包括节点名、属性名、`<string>` 类型的属性值、路径),类似于 `str` 但未检查是否符合 utf-8 编码
21+
- 格式化 `Str` 不再自带引号
22+
- 补全文档并禁止不写文档
1823

1924
---
2025

2126
- standardize the change log
27+
- uses an encapsulated `Str` type uniformly for strings (including node name, property name, property value of `<string>`, path), similar to `str` but not checked for utf-8 encoding
28+
- will not add quotes when formating `Str`
29+
- completes documentation and missing documentation is denied from now on
2230

2331
## [0.1.3](https://github.com/YdrMaster/dtb-walker/releases/tag/v0.1.3) - 2022-06-30
2432

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
[package]
22
name = "dtb-walker"
33
description = "A simple package for DTB depth-first walking."
4-
version = "0.1.3"
4+
version = "0.2.0"
55
edition = "2021"
66
authors = ["YdrMaster <[email protected]>"]
77
repository = "https://github.com/YdrMaster/dtb-walker.git"
8+
documentation = "https://docs.rs/dtb-walker"
89
license = "MIT"
910
readme = "README.md"
1011
keywords = ["device-tree", "dtb"]
1112
categories = ["no-std"]
12-
13-
[dependencies]

examples/qemu-virt.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ fn main() {
2222
.unwrap();
2323
dtb.walk(|path, obj| match obj {
2424
DtbObj::SubNode { name } => {
25-
println!("{}{path}/{}", indent(path.level(), INDENT_WIDTH), unsafe {
26-
core::str::from_utf8_unchecked(name)
27-
});
25+
println!("{}{path}/{name}", indent(path.level(), INDENT_WIDTH));
2826
WalkOperation::StepInto
2927
}
3028
DtbObj::Property(prop) => {

src/header.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,60 @@ pub(crate) struct FdtHeader {
1616
pub size_dt_struct: U32BigEndian,
1717
}
1818

19-
#[derive(Debug)]
19+
/// 首部检查可能发现的错误类型。
20+
#[derive(Clone, PartialEq, Eq, Debug)]
2021
pub enum HeaderError {
22+
/// 设备树整体不对齐。
2123
Misaligned(u32),
24+
/// `magic` 字段不是 0xd00dfeed。
2225
Magic(u32),
26+
/// 版本不兼容。
2327
Version(u32),
28+
/// 最后兼容版本不兼容。
2429
LastCompVersion(u32),
30+
/// 设备树总大小不合理。
2531
TotalSize(u32),
32+
/// 结构块偏移不对齐。
2633
StructMisaligned(u32),
27-
StructOffset { value: u32, expected: Range<u32> },
28-
StructSize { value: u32, max: u32 },
34+
/// 结构块偏移不合理。
35+
StructOffset {
36+
/// 解析出的结构块偏移。
37+
value: u32,
38+
/// 可接受的结构块偏移。
39+
expected: Range<u32>,
40+
},
41+
/// 结构块大小不合理。
42+
StructSize {
43+
/// 解析出的结构块大小。
44+
value: u32,
45+
/// 可接受的最大结构块。
46+
max: u32,
47+
},
48+
/// 结构块内容不合理,即没有根节点或不以 END 标记结尾。
2949
StructContent,
50+
/// 地址保护区偏移不对齐。
3051
MemRsvMisaligned(u32),
31-
MemRsvOffset { value: u32, expected: Range<u32> },
32-
StringsOffset { value: u32, expected: Range<u32> },
33-
StringsSize { value: u32, max: u32 },
52+
/// 地址保护区偏移不合理。
53+
MemRsvOffset {
54+
/// 解析出的地址保护区偏移。
55+
value: u32,
56+
/// 可接受的地址保护区偏移。
57+
expected: Range<u32>,
58+
},
59+
/// 字符串区偏移不合理。
60+
StringsOffset {
61+
/// 解析出的字符串区偏移。
62+
value: u32,
63+
/// 可接受的字符串区偏移。
64+
expected: Range<u32>,
65+
},
66+
/// 字符串区大小不合理。
67+
StringsSize {
68+
/// 解析出的字符串区大小。
69+
value: u32,
70+
/// 可接受的字符串区大小。
71+
max: u32,
72+
},
3473
}
3574

3675
const FOUR: usize = 4;

src/indent.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ pub struct Indent {
55
width: usize,
66
}
77

8+
/// 构造一个 `level` 级,每级宽 `width` 的缩进。
89
#[inline]
9-
pub fn indent(level: usize, width: usize) -> Indent {
10+
pub const fn indent(level: usize, width: usize) -> Indent {
1011
Indent { level, width }
1112
}
1213

src/lib.rs

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1+
//! A simple package for DTB depth-first walking.
2+
//!
3+
//! # Example
4+
//!
5+
//! ```cmd
6+
//! cargo run --release --example qemu-virt
7+
//! ```
8+
//!
9+
//! # Usage
10+
//!
11+
//! ```rust,no_run
12+
//! Dtb::from_raw_parts(dtb).unwrap()
13+
//! ```
14+
115
#![no_std]
2-
#![deny(warnings)] // cancel this line during developing
16+
#![deny(warnings, unstable_features, missing_docs)] // cancel this line during developing
317

418
mod header;
519
mod indent;
@@ -9,8 +23,10 @@ mod structure_block;
923
mod walker;
1024

1125
pub use path::Path;
12-
pub use property::{PHandle, Property, Reg, Str, StrList};
26+
pub use property::{PHandle, Property, Reg, StrList};
1327
pub mod utils {
28+
//! 用于设备树解析、格式化的工具集。
29+
1430
pub use crate::indent::indent;
1531
}
1632
pub use header::HeaderError;
@@ -64,9 +80,12 @@ impl Dtb<'static> {
6480
}
6581
}
6682

83+
/// 从内存切片构造设备树二进制对象失败。
6784
pub enum ConvertError {
68-
Truncated,
85+
/// 首部检查未通过。
6986
Header(HeaderError),
87+
/// 切片未能容纳整个设备树。
88+
Truncated,
7089
}
7190

7291
impl<'a> Dtb<'a> {
@@ -127,24 +146,61 @@ impl Dtb<'_> {
127146

128147
/// 设备树二进制小对象。
129148
pub enum DtbObj<'a> {
130-
/// 子节点
131-
SubNode { name: &'a [u8] },
132-
/// 一般属性
149+
/// 子节点。
150+
SubNode {
151+
/// 节点名。
152+
name: Str<'a>,
153+
},
154+
/// 一般属性。
133155
Property(Property<'a>),
134156
}
135157

136158
/// 遍历操作。
137159
pub enum WalkOperation {
138-
/// 进入子节点
160+
/// 进入子节点
139161
StepInto,
140-
/// 跳过子节点
162+
/// 跳过子节点
141163
StepOver,
142-
/// 跳过当前子树
164+
/// 跳过当前子树
143165
StepOut,
144-
/// 结束遍历
166+
/// 结束遍历
145167
Terminate,
146168
}
147169

170+
/// 地址空间上的一个字符串,但未检查是否符合 utf-8 编码。
171+
#[derive(Clone, Copy)]
172+
pub struct Str<'a>(&'a [u8]);
173+
174+
impl Str<'_> {
175+
/// Converts to `&[u8]`.
176+
#[inline]
177+
pub fn as_bytes(&self) -> &[u8] {
178+
self.0
179+
}
180+
181+
/// Converts to [`str`].
182+
#[inline]
183+
pub fn as_str(&self) -> Result<&str, core::str::Utf8Error> {
184+
core::str::from_utf8(self.0)
185+
}
186+
187+
/// Converts to [`str`] without checking utf-8 validity.
188+
///
189+
/// # Safety
190+
///
191+
/// see [`core::str::from_utf8_unchecked`].
192+
#[inline]
193+
pub unsafe fn as_str_unchecked(&self) -> &str {
194+
core::str::from_utf8_unchecked(self.0)
195+
}
196+
}
197+
198+
impl fmt::Display for Str<'_> {
199+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200+
unsafe { self.as_str_unchecked() }.fmt(f)
201+
}
202+
}
203+
148204
#[repr(transparent)]
149205
#[derive(Clone, Copy, PartialEq, Eq)]
150206
struct U32BigEndian(u32);

src/path.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
use core::{fmt, str};
1+
use crate::Str;
2+
use core::{fmt, str};
23

34
/// 设备树节点路径。
45
pub struct Path<'a> {
56
pub(crate) parent: Option<&'a Path<'a>>,
6-
pub(crate) name: &'a [u8],
7+
pub(crate) name: Str<'a>,
78
}
89

910
impl Path<'_> {
1011
pub(crate) const ROOT: Self = Self {
1112
parent: None,
12-
name: &[],
13+
name: Str(&[]),
1314
};
1415

1516
/// 返回路径层数。定义根节点的子节点层数为 0。
@@ -24,10 +25,16 @@ impl Path<'_> {
2425

2526
/// 返回路径最后一级的节点名。
2627
#[inline]
27-
pub fn last(&self) -> &[u8] {
28+
pub fn last(&self) -> Str {
2829
self.name
2930
}
3031

32+
/// 如果这是根节点的路径则返回 `true`。
33+
#[inline]
34+
pub fn is_root(&self) -> bool {
35+
self.name.0.is_empty()
36+
}
37+
3138
/// 将路径字符串格式化到 `buf` 中。
3239
///
3340
/// 如果返回 `Ok(n)`,表示字符串长度为 `n`(`n` 不大于 `buf.len()`)。
@@ -42,12 +49,12 @@ impl Path<'_> {
4249
mut rest => {
4350
buf[len] = b'/';
4451
rest -= 1;
45-
if self.name.len() > rest {
46-
buf[len + 1..].copy_from_slice(&self.name[..rest]);
52+
if self.name.0.len() > rest {
53+
buf[len + 1..].copy_from_slice(&self.name.0[..rest]);
4754
Err(buf.len())
4855
} else {
49-
buf[len + 1..][..self.name.len()].copy_from_slice(self.name);
50-
Ok(len + self.name.len() + 1)
56+
buf[len + 1..][..self.name.0.len()].copy_from_slice(self.name.0);
57+
Ok(len + self.name.0.len() + 1)
5158
}
5259
}
5360
}
@@ -59,7 +66,7 @@ impl fmt::Display for Path<'_> {
5966
if let Some(parent) = self.parent {
6067
parent.fmt(f)?;
6168
'/'.fmt(f)?;
62-
unsafe { str::from_utf8_unchecked(self.name) }.fmt(f)
69+
unsafe { str::from_utf8_unchecked(self.name.0) }.fmt(f)
6370
} else {
6471
Ok(())
6572
}

src/property/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ mod phandle;
44
mod reg;
55
mod str;
66

7-
use crate::StructureBlock;
7+
use crate::{Str, StructureBlock};
88
use core::{fmt, slice};
99

1010
pub use self::phandle::PHandle;
11-
pub use self::str::{Str, StrList};
11+
pub use self::str::StrList;
1212
pub use reg::Reg;
1313
pub(crate) use reg::RegCfg;
1414

@@ -29,7 +29,12 @@ pub enum Property<'a> {
2929
/// §2.3.10 DMA 连贯性
3030
DmaCoherent,
3131
/// 一般属性
32-
General { name: Str<'a>, value: &'a [u8] },
32+
General {
33+
/// 属性名
34+
name: Str<'a>,
35+
/// 属性值
36+
value: &'a [u8],
37+
},
3338
}
3439

3540
struct Error;

src/property/phandle.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
use core::fmt;
1+
//! §2.3.3
22
3+
use core::fmt;
4+
5+
/// §2.3.3 phandle 属性
36
pub struct PHandle(pub(super) u32);
47

58
impl PHandle {
9+
/// 返回 phandle 值。
610
#[inline]
711
pub fn value(&self) -> u32 {
812
self.0

0 commit comments

Comments
 (0)