1use serde::de::{Error, SeqAccess, Visitor};
17use serde::ser::SerializeSeq;
18use serde::{Deserializer, Serializer};
19
20const PREFIX: &str = "INSPECT:";
21
22pub fn serialize<S>(
23 selectors: &Vec<fidl_fuchsia_diagnostics::Selector>,
24 serializer: S,
25) -> Result<S::Ok, S::Error>
26where
27 S: Serializer,
28{
29 let mut seq = serializer.serialize_seq(Some(selectors.len()))?;
30
31 for selector in selectors {
32 seq.serialize_element(&format!(
33 "{PREFIX}{}",
34 selectors::selector_to_string(selector, selectors::SelectorDisplayOptions::default())
35 .map_err(serde::ser::Error::custom)?
36 ))?;
37 }
38
39 seq.end()
40}
41
42pub fn deserialize<'de, D>(
43 deserializer: D,
44) -> Result<Vec<fidl_fuchsia_diagnostics::Selector>, D::Error>
45where
46 D: Deserializer<'de>,
47{
48 deserializer.deserialize_seq(SelectorsVisitor)
49}
50
51struct SelectorsVisitor;
52
53impl<'de> Visitor<'de> for SelectorsVisitor {
54 type Value = Vec<fidl_fuchsia_diagnostics::Selector>;
55
56 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(formatter, "should be a list of string selectors starting with {}", PREFIX)
58 }
59
60 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
61 where
62 A: SeqAccess<'de>,
63 {
64 let mut selectors = Vec::new();
65 while let Some(v) = seq.next_element::<String>()? {
66 let Some(rest) = v.strip_prefix(PREFIX) else {
67 return Err(A::Error::custom(format!(
68 "Expected selector with prefix \"{}\", got \"{v}\"",
69 PREFIX
70 )));
71 };
72 selectors.push(
73 selectors::parse_selector::<selectors::VerboseError>(rest)
74 .map_err(|e| A::Error::custom(e))?,
75 );
76 }
77 Ok(selectors)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use fidl_fuchsia_diagnostics::Selector;
85 use pretty_assertions::assert_eq;
86 use serde::{Deserialize, Serialize};
87 use test_case::test_case;
88
89 #[derive(Debug, Serialize, Deserialize, PartialEq)]
90 #[serde(transparent)]
91 struct TestConfig {
92 #[serde(with = "crate::inspect")]
93 selectors: Vec<Selector>,
94 }
95
96 #[test_case("a/b:c:d" ; "with_basic_full_selector")]
97 #[test_case("a/b:c" ; "with_basic_partial_selector")]
98 #[test_case(r"a/b:c/d\/e:f" ; "with_escaped_forward_slash")]
99 #[test_case(r"a/b:[name=cd-e]f:g" ; "with_non_default_name")]
100 #[test_case(r#"a:[name="bc-d"]e:f"# ; "with_unneeded_name_quotes")]
101 #[test_case(r#"a:[name="b[]c"]d:e"# ; "with_needed_name_quotes")]
102 #[test_case("a/b:[...]c:d" ; "with_all_names")]
103 #[test_case(r#"a/b:[name=c, name="d", name="f[]g"]h:i"# ; "with_name_list")]
104 #[test_case(r"a\:b/c:d:e" ; "with_collection")]
105 #[test_case(r"a/b/c*d:e:f" ; "with_wildcard_component")]
106 #[test_case(r"a/b:c*/d:e" ; "with_wildcard_tree")]
107 #[test_case(r"a/b:c\*/d:e" ; "with_escaped_wildcard_tree")]
108 #[test_case(r"a/b/c/d:e/f:g*" ; "with_wildcard_property")]
109 #[test_case("a/b/c/d:e/f/g/h:k" ; "with_deep_nesting")]
110 #[fuchsia::test]
111 fn test_serialization(selector: &str) {
112 let selector_escaped = serde_json::to_string(&format!("{PREFIX}{selector}")).unwrap();
114
115 let deserialized: TestConfig =
116 serde_json::from_str(&format!("[{selector_escaped}]")).unwrap();
117 let serialized = serde_json::to_string(&deserialized).unwrap();
118 let deserialized_again: TestConfig = serde_json::from_str(&serialized).unwrap();
119 assert_eq!(deserialized, deserialized_again);
120 assert_eq!(deserialized.selectors, vec![selectors::parse_verbose(selector).unwrap()]);
121 }
122
123 #[test_case("🦀a🦀" ; "unicode_split_at_boundary_emoji")]
124 #[test_case("日本語" ; "unicode_split_at_boundary_cjk")]
125 #[test_case("test:🔥" ; "unicode_split_at_boundary_short_prefix")]
126 #[fuchsia::test]
127 fn test_deserialization_invalid_prefix_unicode(input: &str) {
128 let json = serde_json::to_string(&vec![input]).unwrap();
129 let result = serde_json::from_str::<TestConfig>(&json);
130 assert!(result.is_err());
131 }
132}