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}