1use std::mem::size_of_val;
8
9use crate::fdt::c_str_to_string;
10use crate::fdt::Error;
11use crate::fdt::Result;
12use crate::fdt::SIZE_U32;
13use crate::fdt::SIZE_U64;
14
15pub trait ToFdtPropval {
20 fn to_propval(self) -> Result<Vec<u8>>;
22}
23
24#[inline]
25fn u32_to_bytes(value: &[u32]) -> Vec<u8> {
26 let mut bytes = Vec::with_capacity(size_of_val(value));
27 for val in value {
28 bytes.extend_from_slice(&val.to_be_bytes())
29 }
30 bytes
31}
32
33#[inline]
34fn u64_to_bytes(value: &[u64]) -> Vec<u8> {
35 let mut bytes = Vec::with_capacity(size_of_val(value));
36 for val in value {
37 bytes.extend_from_slice(&val.to_be_bytes())
38 }
39 bytes
40}
41
42impl ToFdtPropval for () {
43 fn to_propval(self) -> Result<Vec<u8>> {
44 Ok(vec![])
45 }
46}
47
48impl ToFdtPropval for &[u8] {
49 fn to_propval(self) -> Result<Vec<u8>> {
50 Ok(self.into())
51 }
52}
53
54impl<const N: usize> ToFdtPropval for &[u8; N] {
55 fn to_propval(self) -> Result<Vec<u8>> {
56 Ok(self.to_vec())
57 }
58}
59
60impl ToFdtPropval for Vec<u8> {
61 fn to_propval(self) -> Result<Vec<u8>> {
62 Ok(self)
63 }
64}
65
66impl ToFdtPropval for u32 {
67 fn to_propval(self) -> Result<Vec<u8>> {
68 Ok(u32_to_bytes(std::slice::from_ref(&self)))
69 }
70}
71
72impl ToFdtPropval for &[u32] {
73 fn to_propval(self) -> Result<Vec<u8>> {
74 Ok(u32_to_bytes(self))
75 }
76}
77
78impl<const N: usize> ToFdtPropval for &[u32; N] {
79 fn to_propval(self) -> Result<Vec<u8>> {
80 Ok(u32_to_bytes(self))
81 }
82}
83
84impl ToFdtPropval for Vec<u32> {
85 fn to_propval(self) -> Result<Vec<u8>> {
86 Ok(u32_to_bytes(self.as_slice()))
87 }
88}
89
90impl ToFdtPropval for u64 {
91 fn to_propval(self) -> Result<Vec<u8>> {
92 Ok(u64_to_bytes(std::slice::from_ref(&self)))
93 }
94}
95
96impl ToFdtPropval for &[u64] {
97 fn to_propval(self) -> Result<Vec<u8>> {
98 Ok(u64_to_bytes(self))
99 }
100}
101
102impl<const N: usize> ToFdtPropval for &[u64; N] {
103 fn to_propval(self) -> Result<Vec<u8>> {
104 Ok(u64_to_bytes(self))
105 }
106}
107
108impl ToFdtPropval for Vec<u64> {
109 fn to_propval(self) -> Result<Vec<u8>> {
110 Ok(u64_to_bytes(self.as_slice()))
111 }
112}
113
114#[inline]
115fn is_valid_string_property(val: &str) -> bool {
116 !val.contains('\0')
119}
120
121#[inline]
122fn str_to_bytes<T: AsRef<str>>(value: &[T]) -> Result<Vec<u8>> {
123 let total_length = value.iter().map(|s| s.as_ref().len() + 1).sum();
124 let mut bytes = Vec::with_capacity(total_length);
125 for s in value {
126 let s = s.as_ref();
127 if !is_valid_string_property(s) {
128 return Err(Error::InvalidString(s.to_owned()));
129 }
130 bytes.extend_from_slice(s.as_bytes());
131 bytes.push(0);
132 }
133 Ok(bytes)
134}
135
136impl ToFdtPropval for &str {
137 fn to_propval(self) -> Result<Vec<u8>> {
138 str_to_bytes(std::slice::from_ref(&self))
139 }
140}
141
142impl ToFdtPropval for &[&str] {
143 fn to_propval(self) -> Result<Vec<u8>> {
144 str_to_bytes(self)
145 }
146}
147
148impl<const N: usize> ToFdtPropval for &[&str; N] {
149 fn to_propval(self) -> Result<Vec<u8>> {
150 str_to_bytes(self)
151 }
152}
153
154impl ToFdtPropval for String {
155 fn to_propval(self) -> Result<Vec<u8>> {
156 if !is_valid_string_property(&self) {
157 Err(Error::InvalidString(self))
158 } else {
159 let mut bytes = self.into_bytes();
160 bytes.push(0);
161 Ok(bytes)
162 }
163 }
164}
165
166impl ToFdtPropval for Vec<String> {
167 fn to_propval(self) -> Result<Vec<u8>> {
168 str_to_bytes(&self)
169 }
170}
171
172pub trait FromFdtPropval {
177 fn from_propval(propval: &[u8]) -> Option<Self>
179 where
180 Self: Sized;
181}
182
183impl FromFdtPropval for () {
184 fn from_propval(propval: &[u8]) -> Option<Self> {
185 propval.is_empty().then_some(())
186 }
187}
188
189impl FromFdtPropval for Vec<u8> {
190 fn from_propval(propval: &[u8]) -> Option<Self> {
191 Some(propval.into())
192 }
193}
194
195impl FromFdtPropval for u32 {
196 fn from_propval(propval: &[u8]) -> Option<Self> {
197 if propval.len() == SIZE_U32 {
198 Some(u32::from_be_bytes(propval.try_into().unwrap()))
199 } else {
200 None
201 }
202 }
203}
204
205impl FromFdtPropval for Vec<u32> {
206 fn from_propval(propval: &[u8]) -> Option<Self> {
207 if propval.len() % SIZE_U32 != 0 {
208 None
209 } else {
210 Some(
211 propval
212 .chunks(SIZE_U32)
213 .map(|v| u32::from_be_bytes(v.try_into().unwrap()))
214 .collect(),
215 )
216 }
217 }
218}
219
220impl FromFdtPropval for u64 {
221 fn from_propval(propval: &[u8]) -> Option<Self> {
222 if propval.len() == SIZE_U64 {
223 Some(u64::from_be_bytes(propval.try_into().unwrap()))
224 } else {
225 None
226 }
227 }
228}
229
230impl FromFdtPropval for Vec<u64> {
231 fn from_propval(propval: &[u8]) -> Option<Self> {
232 if propval.len() % SIZE_U64 != 0 {
233 None
234 } else {
235 Some(
236 propval
237 .chunks(SIZE_U64)
238 .map(|v| u64::from_be_bytes(v.try_into().unwrap()))
239 .collect(),
240 )
241 }
242 }
243}
244
245impl FromFdtPropval for String {
246 fn from_propval(propval: &[u8]) -> Option<Self> {
247 c_str_to_string(propval)
248 }
249}
250
251impl FromFdtPropval for Vec<String> {
252 fn from_propval(propval: &[u8]) -> Option<Self> {
253 if Some(&0) == propval.last() {
254 Some(
255 propval
256 .split(|&b| b == 0u8)
257 .take_while(|s| !s.is_empty())
258 .filter_map(|b| String::from_utf8(b.into()).ok())
259 .collect(),
260 )
261 } else {
262 None
263 }
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 #[test]
272 fn fdt_as_propval() {
273 assert_eq!(().to_propval().unwrap(), []);
274 assert_eq!([0u8, 1u8, 2u8].to_propval().unwrap(), [0u8, 1u8, 2u8]);
275 assert_eq!(0x1u32.to_propval().unwrap(), [0u8, 0, 0, 1]);
276 assert_eq!(
277 0x12345678u32.to_propval().unwrap(),
278 [0x12u8, 0x34, 0x56, 0x78]
279 );
280 assert_eq!(
281 0x12345678ABCDu64.to_propval().unwrap(),
282 [0x00u8, 0x00, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD]
283 );
284 assert_eq!(
285 [0x1u32, 0xABCDu32].to_propval().unwrap(),
286 [0x00u8, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD]
287 );
288 assert_eq!(
289 [0x1u64, 0xABCD00000000u64].to_propval().unwrap(),
290 [
291 0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD, 0x00,
292 0x00, 0x00, 0x00,
293 ]
294 );
295 assert_eq!(
296 "abc def".to_propval().unwrap(),
297 [0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00,]
298 );
299 assert_eq!(
300 ["abc def", "ghi jkl", "mno pqr"].to_propval().unwrap(),
301 [
302 0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68, 0x69, 0x20, 0x6A,
303 0x6B, 0x6C, 0x00, 0x6Du8, 0x6E, 0x6F, 0x20, 0x70, 0x71, 0x72, 0x00,
304 ]
305 );
306 "abc\0def".to_propval().expect_err("invalid string");
307 }
308
309 #[test]
310 fn fdt_from_propval() {
311 assert_eq!(Vec::<u8>::from_propval(&[]).unwrap(), []);
312 assert_eq!(u32::from_propval(&[0, 0, 0, 1]).unwrap(), 1u32);
313 assert_eq!(
314 u32::from_propval(&[0x12u8, 0x34, 0x56, 0x78]).unwrap(),
315 0x12345678u32
316 );
317 assert_eq!(
318 u64::from_propval(&[0x00u8, 0x00, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD]).unwrap(),
319 0x12345678ABCDu64
320 );
321 assert_eq!(
322 Vec::<u32>::from_propval(&[0x00u8, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD]).unwrap(),
323 [0x1u32, 0xABCDu32]
324 );
325 assert_eq!(
326 Vec::<u64>::from_propval(&[
327 0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD, 0x00,
328 0x00, 0x00, 0x00
329 ])
330 .unwrap(),
331 [0x1u64, 0xABCD00000000u64]
332 );
333 assert_eq!(
334 String::from_propval(&[0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00]).unwrap(),
335 "abc def"
336 );
337 assert_eq!(
338 Vec::<String>::from_propval(&[
339 0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68, 0x69, 0x20, 0x6A,
340 0x6B, 0x6C, 0x00, 0x6Du8, 0x6E, 0x6F, 0x20, 0x70, 0x71, 0x72, 0x00,
341 ])
342 .unwrap(),
343 ["abc def", "ghi jkl", "mno pqr"],
344 );
345
346 assert!(Vec::<String>::from_propval(&[
347 0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68,
348 ])
349 .is_none());
350 assert!(String::from_propval(&[0x61u8, 0x62, 0x63]).is_none());
351 assert!(u32::from_propval(&[0x61u8, 0x62]).is_none());
352 assert!(u64::from_propval(&[0x61u8, 0x62, 0x61u8, 0x62, 0x61u8, 0x62]).is_none());
353 }
354}