Skip to main content

fdf_metadata/
serde.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fidl_fuchsia_driver_metadata as fmetadata;
6use std::collections::BTreeMap;
7
8/// Error type for deserialization failures.
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11    #[error("Missing key in dictionary entry")]
12    MissingKey,
13    #[error("Missing value in dictionary entry")]
14    MissingValue,
15    #[error("Custom error: {0}")]
16    Custom(String),
17}
18
19impl serde::de::Error for Error {
20    fn custom<T: std::fmt::Display>(msg: T) -> Self {
21        Error::Custom(msg.to_string())
22    }
23}
24
25/// Deserializes a `fuchsia.driver.metadata.Dictionary` into a type `T` that implements `Deserialize`.
26pub fn from_dictionary<T>(dict: fmetadata::Dictionary) -> Result<T, Error>
27where
28    T: serde::de::DeserializeOwned,
29{
30    let mut entries = BTreeMap::new();
31    if let Some(e) = dict.entries {
32        for entry in e {
33            entries.insert(entry.key, entry.value);
34        }
35    }
36    let deserializer = DictionaryDeserializer { entries: &entries, prefix: "".to_string() };
37    let result = T::deserialize(deserializer)?;
38    Ok(result)
39}
40
41fn bytes_from_seq<'de, A>(mut seq: A) -> Result<Vec<u8>, A::Error>
42where
43    A: serde::de::SeqAccess<'de>,
44{
45    let mut bytes = Vec::new();
46    while let Some(val) = seq.next_element::<i64>()? {
47        let b = (val as u32).to_be_bytes();
48        bytes.extend_from_slice(&b);
49    }
50    Ok(bytes)
51}
52
53/// A wrapper type for a vector of strings deserialized from devicetree properties (integer vectors).
54/// Strings are assumed to be null-terminated and concatenated.
55#[derive(Debug, PartialEq, Clone)]
56pub struct StringVec(pub Vec<String>);
57
58impl<'de> serde::Deserialize<'de> for StringVec {
59    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60    where
61        D: serde::Deserializer<'de>,
62    {
63        struct Visitor;
64        impl<'de> serde::de::Visitor<'de> for Visitor {
65            type Value = Vec<String>;
66            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67                formatter.write_str("a sequence of integers representing concatenated strings")
68            }
69            fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
70            where
71                A: serde::de::SeqAccess<'de>,
72            {
73                let bytes = bytes_from_seq(seq)?;
74                let strings = bytes
75                    .split(|&b| b == 0)
76                    .filter(|s| !s.is_empty())
77                    .map(|s| String::from_utf8_lossy(s).to_string())
78                    .collect();
79                Ok(strings)
80            }
81        }
82        Ok(StringVec(deserializer.deserialize_seq(Visitor)?))
83    }
84}
85
86impl std::ops::Deref for StringVec {
87    type Target = Vec<String>;
88    fn deref(&self) -> &Self::Target {
89        &self.0
90    }
91}
92
93struct DictionaryDeserializer<'a> {
94    entries: &'a BTreeMap<String, fmetadata::DictionaryValue>,
95    prefix: String,
96}
97
98impl<'de, 'a> serde::Deserializer<'de> for DictionaryDeserializer<'a> {
99    type Error = Error;
100
101    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
102    where
103        V: serde::de::Visitor<'de>,
104    {
105        if let Some(val) = self.entries.get(&self.prefix) {
106            match val {
107                fmetadata::DictionaryValue::Int64(i) => visitor.visit_i64(*i),
108                fmetadata::DictionaryValue::Int64Vec(v) => {
109                    visitor.visit_seq(SeqDeserializer { vec: v.clone(), index: 0 })
110                }
111                _ => Err(Error::Custom("Unsupported value type".to_string())),
112            }
113        } else {
114            visitor.visit_map(MapDeserializer::new(self.entries, &self.prefix))
115        }
116    }
117
118    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
119    where
120        V: serde::de::Visitor<'de>,
121    {
122        if let Some(val) = self.entries.get(&self.prefix) {
123            if let fmetadata::DictionaryValue::Int64Vec(v) = val {
124                let mut bytes = Vec::new();
125                for val in v {
126                    let b = (*val as u32).to_be_bytes();
127                    bytes.extend_from_slice(&b);
128                }
129                if let Some(null_pos) = bytes.iter().position(|&b| b == 0) {
130                    bytes.truncate(null_pos);
131                }
132                let s = String::from_utf8_lossy(&bytes).to_string();
133                return visitor.visit_string(s);
134            }
135        }
136        self.deserialize_any(visitor)
137    }
138
139    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
140    where
141        V: serde::de::Visitor<'de>,
142    {
143        self.deserialize_string(visitor)
144    }
145
146    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
147    where
148        V: serde::de::Visitor<'de>,
149    {
150        if let Some(val) = self.entries.get(&self.prefix) {
151            if let fmetadata::DictionaryValue::Int64Vec(v) = val {
152                if v.is_empty() {
153                    return visitor.visit_bool(true);
154                }
155            }
156        }
157        self.deserialize_any(visitor)
158    }
159
160    serde::forward_to_deserialize_any! {
161        i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char
162        bytes byte_buf option unit unit_struct newtype_struct seq tuple
163        tuple_struct map struct enum identifier ignored_any
164    }
165}
166
167struct MapDeserializer<'a> {
168    entries: &'a BTreeMap<String, fmetadata::DictionaryValue>,
169    prefix: String,
170    keys: Vec<String>,
171    current_index: usize,
172}
173
174impl<'a> MapDeserializer<'a> {
175    fn new(entries: &'a BTreeMap<String, fmetadata::DictionaryValue>, prefix: &str) -> Self {
176        let mut keys = std::collections::HashSet::new();
177        let prefix_with_dot =
178            if prefix.is_empty() { "".to_string() } else { format!("{}.", prefix) };
179
180        for k in entries.keys() {
181            if k.starts_with(&prefix_with_dot) || prefix.is_empty() {
182                let stripped =
183                    if prefix.is_empty() { k.as_str() } else { &k[prefix_with_dot.len()..] };
184                let child_key = match stripped.find('.') {
185                    Some(idx) => &stripped[..idx],
186                    None => stripped,
187                };
188                keys.insert(child_key.to_string());
189            }
190        }
191        let mut keys_vec: Vec<String> = keys.into_iter().collect();
192        keys_vec.sort();
193        Self { entries, prefix: prefix.to_string(), keys: keys_vec, current_index: 0 }
194    }
195}
196
197impl<'de, 'a> serde::de::MapAccess<'de> for MapDeserializer<'a> {
198    type Error = Error;
199
200    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
201    where
202        K: serde::de::DeserializeSeed<'de>,
203    {
204        if self.current_index >= self.keys.len() {
205            return Ok(None);
206        }
207        let key = &self.keys[self.current_index];
208        seed.deserialize(KeyDeserializer { key: key.clone() }).map(Some)
209    }
210
211    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
212    where
213        V: serde::de::DeserializeSeed<'de>,
214    {
215        let key = &self.keys[self.current_index];
216        self.current_index += 1;
217
218        let new_prefix =
219            if self.prefix.is_empty() { key.clone() } else { format!("{}.{}", self.prefix, key) };
220
221        seed.deserialize(DictionaryDeserializer { entries: self.entries, prefix: new_prefix })
222    }
223}
224
225struct KeyDeserializer {
226    key: String,
227}
228
229impl<'de> serde::Deserializer<'de> for KeyDeserializer {
230    type Error = Error;
231
232    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
233    where
234        V: serde::de::Visitor<'de>,
235    {
236        visitor.visit_string(self.key)
237    }
238
239    serde::forward_to_deserialize_any! {
240        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
241        bytes byte_buf option unit unit_struct newtype_struct seq tuple
242        tuple_struct map struct enum identifier ignored_any
243    }
244}
245
246struct SeqDeserializer {
247    vec: Vec<i64>,
248    index: usize,
249}
250
251impl<'de> serde::de::SeqAccess<'de> for SeqDeserializer {
252    type Error = Error;
253
254    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
255    where
256        T: serde::de::DeserializeSeed<'de>,
257    {
258        if self.index >= self.vec.len() {
259            return Ok(None);
260        }
261        let val = self.vec[self.index];
262        self.index += 1;
263        seed.deserialize(I64Deserializer { val }).map(Some)
264    }
265}
266
267struct I64Deserializer {
268    val: i64,
269}
270
271impl<'de> serde::Deserializer<'de> for I64Deserializer {
272    type Error = Error;
273
274    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
275    where
276        V: serde::de::Visitor<'de>,
277    {
278        visitor.visit_i64(self.val)
279    }
280
281    serde::forward_to_deserialize_any! {
282        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
283        bytes byte_buf option unit unit_struct newtype_struct seq tuple
284        tuple_struct map struct enum identifier ignored_any
285    }
286}
287
288#[cfg(test)]
289mod tests {
290    use super::*;
291    use serde::Deserialize;
292
293    #[derive(Deserialize, Debug, PartialEq)]
294    struct MyConfig {
295        test_str: String,
296        test_int: i64,
297        test_vec: StringVec,
298        nested: NestedConfig,
299    }
300
301    #[derive(Deserialize, Debug, PartialEq)]
302    struct NestedConfig {
303        inner_val: String,
304    }
305
306    #[test]
307    fn test_deserialization() {
308        let mut entries = Vec::new();
309
310        // "hello" -> [104, 101, 108, 108], [111, 0, 0, 0]
311        let str_val1 = i64::from(u32::from_be_bytes([104, 101, 108, 108]));
312        let str_val2 = i64::from(u32::from_be_bytes([111, 0, 0, 0]));
313
314        entries.push(fmetadata::DictionaryEntry {
315            key: "test_str".to_string(),
316            value: fmetadata::DictionaryValue::Int64Vec(vec![str_val1, str_val2]),
317        });
318        entries.push(fmetadata::DictionaryEntry {
319            key: "test_int".to_string(),
320            value: fmetadata::DictionaryValue::Int64(42),
321        });
322
323        // "a\0b\0" -> [97, 0, 98, 0]
324        let vec_val = i64::from(u32::from_be_bytes([97, 0, 98, 0]));
325        entries.push(fmetadata::DictionaryEntry {
326            key: "test_vec".to_string(),
327            value: fmetadata::DictionaryValue::Int64Vec(vec![vec_val]),
328        });
329
330        // "secret" -> [115, 101, 99, 114], [101, 116, 0, 0]
331        let sec_val1 = i64::from(u32::from_be_bytes([115, 101, 99, 114]));
332        let sec_val2 = i64::from(u32::from_be_bytes([101, 116, 0, 0]));
333
334        entries.push(fmetadata::DictionaryEntry {
335            key: "nested.inner_val".to_string(),
336            value: fmetadata::DictionaryValue::Int64Vec(vec![sec_val1, sec_val2]),
337        });
338
339        let dict = fmetadata::Dictionary { entries: Some(entries), ..Default::default() };
340
341        let config: MyConfig = from_dictionary(dict).unwrap();
342        assert_eq!(
343            config,
344            MyConfig {
345                test_str: "hello".to_string(),
346                test_int: 42,
347                test_vec: StringVec(vec!["a".to_string(), "b".to_string()]),
348                nested: NestedConfig { inner_val: "secret".to_string() },
349            }
350        );
351    }
352
353    #[derive(Deserialize, Debug, PartialEq)]
354    struct BoolConfig {
355        test_bool: bool,
356    }
357
358    #[test]
359    fn test_bool_deserialization() {
360        let mut entries = Vec::new();
361        entries.push(fmetadata::DictionaryEntry {
362            key: "test_bool".to_string(),
363            value: fmetadata::DictionaryValue::Int64Vec(vec![]),
364        });
365
366        let dict = fmetadata::Dictionary { entries: Some(entries), ..Default::default() };
367
368        let config: BoolConfig = from_dictionary(dict).unwrap();
369        assert_eq!(config, BoolConfig { test_bool: true });
370    }
371}