devicetree_tool/property.rs
1// Copyright (c) 2023, Michael Zhao
2// SPDX-License-Identifier: MIT
3
4use crate::dts_generator::DtsGenerator;
5
6/// A property that describes a characteristic of node.
7///
8/// # Examples
9///
10/// You can create an empty property with a name:
11///
12/// ```
13/// use devicetree_tool::Property;
14///
15/// let prop = Property::new_empty("prop");
16///
17/// assert_eq!(prop.value, vec![]);
18/// ```
19///
20/// Or create a property with value in the type of `u32`, `u64`, `str` or others.
21///
22/// ```
23/// use devicetree_tool::Property;
24///
25/// let prop = Property::new_u32("prop", 42);
26///
27/// assert_eq!(format!("{}", prop), "prop = <0x0 0x0 0x0 0x2a>;\n");
28/// ```
29pub struct Property {
30 pub name: String,
31 pub value: Vec<u8>,
32}
33
34impl Property {
35 /// Create a `Property` with a name, but without any value.
36 ///
37 /// # Example
38 ///
39 /// ```
40 /// use devicetree_tool::Property;
41 ///
42 /// let prop = Property::new_empty("prop");
43 ///
44 /// assert_eq!(prop.value, vec![]);
45 /// assert_eq!(format!("{}", prop), "prop;\n");
46 /// ```
47 pub fn new_empty(name: &str) -> Self {
48 Property {
49 name: String::from(name),
50 value: vec![],
51 }
52 }
53
54 /// Create a named `Property` with the value of type `u32`.
55 ///
56 /// # Example
57 ///
58 /// ```
59 /// use devicetree_tool::Property;
60 ///
61 /// let prop = Property::new_u32("prop", 42);
62 ///
63 /// assert_eq!(prop.value, vec![0u8, 0u8, 0u8, 42u8]);
64 /// assert_eq!(format!("{}", prop), "prop = <0x0 0x0 0x0 0x2a>;\n");
65 /// ```
66 pub fn new_u32(name: &str, value: u32) -> Self {
67 Property {
68 name: String::from(name),
69 value: value.to_be_bytes().to_vec(),
70 }
71 }
72
73 /// Create a named `Property` with the value of type `u64`.
74 ///
75 /// # Example
76 ///
77 /// ```
78 /// use devicetree_tool::Property;
79 ///
80 /// let prop = Property::new_u64("prop", 42);
81 ///
82 /// assert_eq!(prop.value, vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 42u8]);
83 /// assert_eq!(format!("{}", prop), "prop = <0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x2a>;\n");
84 /// ```
85 pub fn new_u64(name: &str, value: u64) -> Self {
86 Property {
87 name: String::from(name),
88 value: value.to_be_bytes().to_vec(),
89 }
90 }
91
92 /// Create a named `Property` with the value of string.
93 ///
94 /// # Example
95 ///
96 /// ```
97 /// use devicetree_tool::Property;
98 ///
99 /// let prop = Property::new_str("prop", "hello");
100 ///
101 /// assert_eq!(prop.value, vec!['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0u8]);
102 /// assert_eq!(format!("{}", prop), "prop = <0x68 0x65 0x6c 0x6c 0x6f 0x0>;\n");
103 /// ```
104 pub fn new_str(name: &str, value: &str) -> Self {
105 let mut bytes: Vec<u8> = value.as_bytes().to_vec();
106 bytes.push(0);
107 Property {
108 name: String::from(name),
109 value: bytes,
110 }
111 }
112
113 /// Create a named `Property` with the value of a string list.
114 ///
115 /// # Example
116 ///
117 /// ```
118 /// use devicetree_tool::Property;
119 ///
120 /// let prop = Property::new_strs("prop", vec!["hello", "abc"]);
121 ///
122 /// assert_eq!(prop.value, vec!['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0u8, 'a' as u8, 'b' as u8, 'c' as u8, 0u8]);
123 /// assert_eq!(format!("{}", prop), "prop = <0x68 0x65 0x6c 0x6c 0x6f 0x0 0x61 0x62 0x63 0x0>;\n");
124 /// ```
125 pub fn new_strs(name: &str, value: Vec<&str>) -> Self {
126 let mut bytes: Vec<u8> = vec![];
127 for v in value {
128 let mut v_bytes = v.as_bytes().to_vec();
129 bytes.append(&mut v_bytes);
130 bytes.push(0)
131 }
132 Property {
133 name: String::from(name),
134 value: bytes,
135 }
136 }
137
138 /// Create a named `Property` with the value of a `u8` array.
139 ///
140 /// # Example
141 ///
142 /// ```
143 /// use devicetree_tool::Property;
144 ///
145 /// let prop = Property::new_u8s("prop", vec![1u8, 2u8, 3u8, 4u8]);
146 ///
147 /// assert_eq!(prop.value, vec![1u8, 2u8, 3u8, 4u8]);
148 /// assert_eq!(format!("{}", prop), "prop = <0x1 0x2 0x3 0x4>;\n");
149 /// ```
150 pub fn new_u8s(name: &str, value: Vec<u8>) -> Self {
151 Property {
152 name: String::from(name),
153 value,
154 }
155 }
156
157 /// Create a named `Property` with the value of a `u32` array.
158 ///
159 /// # Example
160 ///
161 /// ```
162 /// use devicetree_tool::Property;
163 ///
164 /// let prop = Property::new_u32s("prop", vec![1u32, 2u32]);
165 ///
166 /// assert_eq!(prop.value, vec![0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 2u8]);
167 /// assert_eq!(format!("{}", prop), "prop = <0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x2>;\n");
168 /// ```
169 pub fn new_u32s(name: &str, value: Vec<u32>) -> Self {
170 let mut bytes: Vec<u8> = vec![];
171 for v in value {
172 let mut v_bytes = v.to_be_bytes().to_vec();
173 bytes.append(&mut v_bytes)
174 }
175 Property {
176 name: String::from(name),
177 value: bytes,
178 }
179 }
180}
181
182impl std::fmt::Display for Property {
183 /// Print a `Property` in the format of DTS
184 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
185 let s = DtsGenerator::generate_property(self, 0);
186 writeln!(f, "{s}")
187 }
188}
189
190#[cfg(test)]
191mod tests {
192
193 use super::*;
194
195 #[test]
196 fn test_property_none() {
197 let prop = Property::new_empty("name");
198 assert_eq!(prop.value, vec![]);
199 }
200
201 #[test]
202 fn test_property_u32() {
203 let prop = Property::new_u32("name", 42);
204 assert_eq!(prop.value, vec![0u8, 0u8, 0u8, 42u8]);
205 }
206
207 #[test]
208 fn test_property_u64() {
209 let prop = Property::new_u64("name", 42);
210 assert_eq!(prop.value, vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 42u8]);
211 }
212
213 #[test]
214 fn test_property_str() {
215 let prop = Property::new_str("name", "hello abc");
216 assert_eq!(
217 prop.value,
218 vec![
219 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, ' ' as u8, 'a' as u8,
220 'b' as u8, 'c' as u8, 0
221 ]
222 );
223 }
224
225 #[test]
226 fn test_property_strs() {
227 let strs = vec!["hello", "abc"];
228 let prop = Property::new_strs("name", strs);
229 assert_eq!(
230 prop.value,
231 vec![
232 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 'a' as u8, 'b' as u8,
233 'c' as u8, 0
234 ]
235 );
236 }
237
238 #[test]
239 fn test_property_u8s() {
240 let bytes = vec![0u8, 1u8, 2u8, 3u8];
241 let prop = Property::new_u8s("name", bytes);
242 assert_eq!(prop.value, vec![0u8, 1u8, 2u8, 3u8]);
243 }
244
245 #[test]
246 fn test_property_u32s() {
247 let bytes = vec![0u32, 1u32, 2u32, 3u32];
248 let prop = Property::new_u32s("name", bytes);
249 assert_eq!(
250 prop.value,
251 vec![0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 3u8]
252 );
253 }
254
255 #[test]
256 fn test_property_print() {
257 let prop = Property::new_u32("name", 42);
258 let printing = format!("{}", prop);
259 assert_eq!(&printing, "name = <0x0 0x0 0x0 0x2a>;\n");
260 }
261}