Skip to content

Commit cb8e77c

Browse files
authored
feat: add ToPropertyValue trait (#70)
1 parent d10b59e commit cb8e77c

10 files changed

Lines changed: 265 additions & 63 deletions

File tree

src/fdt_mut.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub use node::FdtNodeMut;
2323
pub use property::FdtPropertyMut;
2424
use zerocopy::{FromBytes, big_endian};
2525

26+
use crate::ToPropertyValue;
2627
use crate::error::{BufferError, FdtParseError};
2728
use crate::fdt::{FDT_NOP, FDT_TAGSIZE, Fdt, FdtHeader, FdtToken};
2829

@@ -326,12 +327,16 @@ impl<B: FdtBuffer> FdtMut<B> {
326327
}
327328
}
328329

329-
fn copy_data_with_padding(&mut self, value: &[u8], padded_val_len: usize, val_offset: usize) {
330+
fn write_property_value_with_padding<T: ToPropertyValue>(
331+
&mut self,
332+
value: &T,
333+
padded_val_len: usize,
334+
val_offset: usize,
335+
) {
336+
let val_len = value.property_value_len();
330337
let data = self.data_mut();
331-
data[val_offset..val_offset + value.len()].copy_from_slice(value);
332-
for i in value.len()..padded_val_len {
333-
data[val_offset + i] = 0;
334-
}
338+
value.write_property_value(&mut data[val_offset..val_offset + val_len]);
339+
data[val_offset + val_len..val_offset + padded_val_len].fill(0);
335340
}
336341
}
337342

src/fdt_mut/node.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::fdt_mut::buffer::FdtBuffer;
1717
use crate::fdt_mut::property::FdtPropMutIter;
1818
use crate::fdt_mut::{FdtMut, FdtPropertyMut};
1919
use crate::standard::{AddressSpaceProperties, NodeStandard};
20-
use crate::{Node, Property};
20+
use crate::{Node, Property, ToPropertyValue};
2121

2222
/// A mutable device tree node.
2323
#[derive(Debug)]
@@ -84,10 +84,10 @@ impl<B: FdtBuffer> FdtNodeMut<'_, B> {
8484
///
8585
/// Panics if the node name or existing structure is invalid, or if lengths
8686
/// exceed `u32::MAX`.
87-
pub fn add_property(
87+
pub fn add_property<T: ToPropertyValue>(
8888
&mut self,
8989
name: &str,
90-
value: &[u8],
90+
value: T,
9191
) -> Result<FdtPropertyMut<'_, B>, crate::error::FdtMutError> {
9292
let nameoff = self.data.add_string(name)? as usize;
9393
let fdt = self.as_read_only().fdt;
@@ -96,15 +96,16 @@ impl<B: FdtBuffer> FdtNodeMut<'_, B> {
9696
offset = Fdt::align_tag_offset(name_end);
9797
let insert_offset = fdt.skip_props(offset, false).expect("valid dt");
9898

99-
let padded_val_len = Fdt::align_tag_offset(value.len());
99+
let val_len = value.property_value_len();
100+
let padded_val_len = Fdt::align_tag_offset(val_len);
100101
let required_space = FDT_TAGSIZE * 3 + padded_val_len;
101102

102103
self.data.shift_dt_struct(insert_offset, required_space)?;
103104

104105
let data = self.data.data_mut();
105106
data[insert_offset..insert_offset + FDT_TAGSIZE].copy_from_slice(&FDT_PROP.to_be_bytes());
106107
data[insert_offset + FDT_TAGSIZE..insert_offset + 2 * FDT_TAGSIZE].copy_from_slice(
107-
&u32::try_from(value.len())
108+
&u32::try_from(val_len)
108109
.expect("len fits in u32")
109110
.to_be_bytes(),
110111
);
@@ -116,12 +117,12 @@ impl<B: FdtBuffer> FdtNodeMut<'_, B> {
116117

117118
let val_offset = insert_offset + 3 * FDT_TAGSIZE;
118119
self.data
119-
.copy_data_with_padding(value, padded_val_len, val_offset);
120+
.write_property_value_with_padding(&value, padded_val_len, val_offset);
120121

121122
Ok(FdtPropertyMut {
122123
prop_offset: insert_offset,
123124
value_offset: val_offset,
124-
len: value.len(),
125+
len: val_len,
125126
nameoff,
126127
data: self.data,
127128
})

src/fdt_mut/property.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ use core::fmt::{Display, Formatter};
1111

1212
use zerocopy::{FromBytes, big_endian};
1313

14-
use crate::Property;
1514
use crate::error::FdtMutError;
1615
use crate::fdt::property::InnerPropIter;
1716
use crate::fdt::{FDT_TAGSIZE, Fdt, FdtProperty};
1817
use crate::fdt_mut::FdtMut;
1918
use crate::fdt_mut::buffer::FdtBuffer;
19+
use crate::{Property, ToPropertyValue};
2020

2121
/// A mutable property of a device tree node.
2222
#[derive(Debug)]
@@ -63,9 +63,10 @@ impl<B: FdtBuffer> FdtPropertyMut<'_, B> {
6363
/// node.property_mut("prop").unwrap().set_value(b"foo\0");
6464
/// assert_eq!(node.property("prop").unwrap().value(), b"foo\0");
6565
/// ```
66-
pub fn set_value(&mut self, new_value: &[u8]) -> Result<(), FdtMutError> {
66+
pub fn set_value<T: ToPropertyValue>(&mut self, new_value: T) -> Result<(), FdtMutError> {
67+
let new_len = new_value.property_value_len();
6768
let old_padded = Fdt::align_tag_offset(self.len);
68-
let new_padded = Fdt::align_tag_offset(new_value.len());
69+
let new_padded = Fdt::align_tag_offset(new_len);
6970

7071
if new_padded > old_padded {
7172
let needed_bytes = new_padded - old_padded;
@@ -87,15 +88,10 @@ impl<B: FdtBuffer> FdtPropertyMut<'_, B> {
8788
&mut self.data.data_mut()[self.prop_offset + FDT_TAGSIZE..],
8889
)
8990
.expect("Fdt should be valid");
90-
len_bytes.set(
91-
new_value
92-
.len()
93-
.try_into()
94-
.expect("length should fit in u32"),
95-
);
91+
len_bytes.set(new_len.try_into().expect("length should fit in u32"));
9692

9793
self.data
98-
.copy_data_with_padding(new_value, new_padded, self.value_offset);
94+
.write_property_value_with_padding(&new_value, new_padded, self.value_offset);
9995

10096
if new_padded < old_padded {
10197
self.data.replace_with_nops(
@@ -104,7 +100,7 @@ impl<B: FdtBuffer> FdtPropertyMut<'_, B> {
104100
);
105101
}
106102

107-
self.len = new_value.len();
103+
self.len = new_len;
108104

109105
Ok(())
110106
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
//! // Add a child node to the root.
6262
//! let child = DeviceTreeNode::builder("child")
6363
//! .unwrap()
64-
//! .property(DeviceTreeProperty::new("my-property", "hello\0").unwrap())
64+
//! .property(DeviceTreeProperty::new("my-property", "hello").unwrap())
6565
//! .build();
6666
//! tree.root.add_child(child);
6767
//!
@@ -133,13 +133,13 @@ pub mod standard;
133133
mod util;
134134
mod validate;
135135
mod values;
136-
137136
use core::fmt::{self, Display, Formatter};
138137
use core::ops::{BitOr, Shl};
139138

140139
use zerocopy::big_endian;
141140

142141
use crate::error::{PropertyError, StandardError};
142+
pub use crate::values::ToPropertyValue;
143143

144144
macro_rules! impl_property_methods {
145145
(get_value = |$self:ident| $get_value:expr) => {

src/model/node.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl<'a> Node for &'a DeviceTreeNode {
150150
/// use dtoolkit::{Node, Property};
151151
///
152152
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
153-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
153+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap());
154154
/// let prop = (&node).property("my-prop").unwrap();
155155
/// assert_eq!(prop.value(), &[1, 2, 3, 4]);
156156
/// ```
@@ -287,9 +287,9 @@ impl DeviceTreeNode {
287287
/// use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
288288
///
289289
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
290-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
290+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap());
291291
/// let prop = node.property_mut("my-prop").unwrap();
292-
/// prop.set_value(vec![5, 6, 7, 8]);
292+
/// prop.set_value(vec![5u8, 6, 7, 8]);
293293
/// assert_eq!((&*prop).value(), &[5, 6, 7, 8]);
294294
/// ```
295295
#[must_use]
@@ -310,7 +310,7 @@ impl DeviceTreeNode {
310310
/// use dtoolkit::{Node, Property};
311311
///
312312
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
313-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
313+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap());
314314
/// assert_eq!((&node).property("my-prop").unwrap().value(), &[1, 2, 3, 4]);
315315
/// ```
316316
pub fn add_property(&mut self, property: DeviceTreeProperty) {
@@ -332,7 +332,7 @@ impl DeviceTreeNode {
332332
/// use dtoolkit::{Node, Property};
333333
///
334334
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
335-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
335+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap());
336336
/// let prop = node.remove_property("my-prop").unwrap();
337337
/// assert_eq!((&prop).value(), &[1, 2, 3, 4]);
338338
/// assert!(node.property("my-prop").is_none());
@@ -361,7 +361,7 @@ impl DeviceTreeNode {
361361
/// let mut node = DeviceTreeNode::new("my-node").unwrap();
362362
/// node.add_child(DeviceTreeNode::new("child").unwrap());
363363
/// let child = node.child_mut("child").unwrap();
364-
/// child.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap());
364+
/// child.add_property(DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap());
365365
/// assert_eq!(
366366
/// (&*child).property("my-prop").unwrap().value(),
367367
/// &[1, 2, 3, 4]
@@ -414,7 +414,7 @@ impl DeviceTreeNode {
414414
/// .property("test")
415415
/// .unwrap()
416416
/// .value(),
417-
/// b"value"
417+
/// b"value\0"
418418
/// );
419419
/// ```
420420
#[must_use]

src/model/overlay.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -482,28 +482,28 @@ mod tests {
482482
fn merge_node_works() {
483483
let mut target = DeviceTreeNode::builder("target")
484484
.unwrap()
485-
.property(DeviceTreeProperty::new("a", vec![1]).unwrap())
485+
.property(DeviceTreeProperty::new("a", vec![1u8]).unwrap())
486486
.child(
487487
DeviceTreeNode::builder("child")
488488
.unwrap()
489-
.property(DeviceTreeProperty::new("c", vec![3]).unwrap())
489+
.property(DeviceTreeProperty::new("c", vec![3u8]).unwrap())
490490
.build(),
491491
)
492492
.build();
493493

494494
let overlay = DeviceTreeNode::builder("overlay")
495495
.unwrap()
496-
.property(DeviceTreeProperty::new("b", vec![4]).unwrap())
496+
.property(DeviceTreeProperty::new("b", vec![4u8]).unwrap())
497497
.child(
498498
DeviceTreeNode::builder("child")
499499
.unwrap()
500-
.property(DeviceTreeProperty::new("d", vec![5]).unwrap())
500+
.property(DeviceTreeProperty::new("d", vec![5u8]).unwrap())
501501
.build(),
502502
)
503503
.child(
504504
DeviceTreeNode::builder("new_child")
505505
.unwrap()
506-
.property(DeviceTreeProperty::new("e", vec![6]).unwrap())
506+
.property(DeviceTreeProperty::new("e", vec![6u8]).unwrap())
507507
.build(),
508508
)
509509
.build();
@@ -521,19 +521,19 @@ mod tests {
521521

522522
let expected = DeviceTreeNode::builder("target")
523523
.unwrap()
524-
.property(DeviceTreeProperty::new("a", vec![1]).unwrap())
525-
.property(DeviceTreeProperty::new("b", vec![4]).unwrap())
524+
.property(DeviceTreeProperty::new("a", vec![1u8]).unwrap())
525+
.property(DeviceTreeProperty::new("b", vec![4u8]).unwrap())
526526
.child(
527527
DeviceTreeNode::builder("child")
528528
.unwrap()
529-
.property(DeviceTreeProperty::new("c", vec![3]).unwrap())
530-
.property(DeviceTreeProperty::new("d", vec![5]).unwrap())
529+
.property(DeviceTreeProperty::new("c", vec![3u8]).unwrap())
530+
.property(DeviceTreeProperty::new("d", vec![5u8]).unwrap())
531531
.build(),
532532
)
533533
.child(
534534
DeviceTreeNode::builder("new_child")
535535
.unwrap()
536-
.property(DeviceTreeProperty::new("e", vec![6]).unwrap())
536+
.property(DeviceTreeProperty::new("e", vec![6u8]).unwrap())
537537
.build(),
538538
)
539539
.build();

src/model/property.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use zerocopy::FromBytes;
1414

1515
use crate::error::ModelError;
1616
use crate::values::{FdtStringListIterator, PropEncodedArrayIterator};
17-
use crate::{Cells, Property};
17+
use crate::{Cells, Property, ToPropertyValue};
1818

1919
/// A mutable, in-memory representation of a device tree property.
2020
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -54,28 +54,27 @@ impl DeviceTreeProperty {
5454
/// use dtoolkit::Property;
5555
/// use dtoolkit::model::DeviceTreeProperty;
5656
///
57-
/// let prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap();
57+
/// let prop = DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap();
5858
/// assert_eq!((&prop).name(), "my-prop");
5959
/// assert_eq!((&prop).value(), &[1, 2, 3, 4]);
6060
/// ```
61-
pub fn new(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Result<Self, ModelError> {
61+
pub fn new<T: ToPropertyValue>(name: impl Into<String>, value: T) -> Result<Self, ModelError> {
6262
let name = name.into();
6363
if !crate::validate::is_valid_property_name(&name) {
6464
return Err(ModelError::InvalidPropertyName(name));
6565
}
66-
Ok(Self {
67-
name,
68-
value: value.into(),
69-
})
66+
Ok(Self::new_unchecked(name, value))
7067
}
7168

7269
/// Creates a new `DeviceTreeProperty` with the given name and value without
7370
/// validation.
7471
#[must_use]
75-
pub fn new_unchecked(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
72+
pub fn new_unchecked<T: ToPropertyValue>(name: impl Into<String>, value: T) -> Self {
73+
let mut vec = alloc::vec![0; value.property_value_len()];
74+
value.write_property_value(&mut vec);
7675
Self {
7776
name: name.into(),
78-
value: value.into(),
77+
value: vec,
7978
}
8079
}
8180

@@ -87,12 +86,13 @@ impl DeviceTreeProperty {
8786
/// use dtoolkit::Property;
8887
/// use dtoolkit::model::DeviceTreeProperty;
8988
///
90-
/// let mut prop = DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]).unwrap();
91-
/// prop.set_value(vec![5, 6, 7, 8]);
89+
/// let mut prop = DeviceTreeProperty::new("my-prop", vec![1u8, 2, 3, 4]).unwrap();
90+
/// prop.set_value(vec![5u8, 6, 7, 8]);
9291
/// assert_eq!((&prop).value(), &[5, 6, 7, 8]);
9392
/// ```
94-
pub fn set_value(&mut self, value: impl Into<Vec<u8>>) {
95-
self.value = value.into();
93+
pub fn set_value<T: ToPropertyValue>(&mut self, value: T) {
94+
self.value.resize(value.property_value_len(), 0);
95+
value.write_property_value(&mut self.value);
9696
}
9797
}
9898

0 commit comments

Comments
 (0)