1 use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
2 use serde::ser::{Serialize, Serializer};
3 use std::collections::HashSet;
4 use std::fmt;
5
6 #[derive(Debug, Clone, Eq, PartialEq)]
7 struct Names {
8 inner: HashSet<String>,
9 }
10
11 impl Serialize for Names {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,12 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
13 where
14 S: Serializer,
15 {
16 let mut names: Vec<_> = self.inner.iter().collect();
17 names.sort();
18 names.serialize(serializer)
19 }
20 }
21
22 impl<'de> Deserialize<'de> for Names {
deserialize<D>(deserializer: D) -> Result<Names, D::Error> where D: Deserializer<'de>,23 fn deserialize<D>(deserializer: D) -> Result<Names, D::Error>
24 where
25 D: Deserializer<'de>,
26 {
27 deserializer.deserialize_any(NamesVisitor)
28 }
29 }
30
31 struct NamesVisitor;
32
33 impl<'de> Visitor<'de> for NamesVisitor {
34 type Value = Names;
35
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result36 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
37 formatter.write_str("names or list of names")
38 }
39
visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: serde::de::Error,40 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
41 where
42 E: serde::de::Error,
43 {
44 let mut out = HashSet::new();
45 out.insert(v.to_string());
46 Ok(Names { inner: out })
47 }
48
visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: SeqAccess<'de>,49 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
50 where
51 A: SeqAccess<'de>,
52 {
53 let mut out: HashSet<String> = HashSet::new();
54
55 // FIXME: Change `&str` to String to make the error go away
56 while let Some(s) = seq.next_element::<&str>()? {
57 out.insert(s.to_string());
58 }
59 Ok(Names { inner: out })
60 }
61 }
62
63 #[test]
64 #[ignore]
65 /// This test is an almost exact replica of the "string or struct" example
66 /// in the [serde guide](https://serde.rs/string-or-struct.html)
67 ///
68 /// FIXME: it currently breaks. If you explicitly select `String` instead
69 /// of `&str` in the FIXME above, it works.
test_visitor()70 fn test_visitor() {
71 let single = r#"
72 ---
73 "foo"
74 "#;
75 let single_expected = Names {
76 inner: {
77 let mut i = HashSet::new();
78 i.insert("foo".into());
79 i
80 },
81 };
82 let multi = r#"
83 ---
84 - "foo"
85 - "bar"
86 "#;
87 let multi_expected = Names {
88 inner: {
89 let mut i = HashSet::new();
90 i.insert("foo".into());
91 i.insert("bar".into());
92 i
93 },
94 };
95
96 let result: Names = serde_yaml::from_str(single).expect("didn't deserialize");
97 assert_eq!(result, single_expected);
98
99 let result: Names = serde_yaml::from_str(multi).expect("didn't deserialize");
100 assert_eq!(result, multi_expected);
101 }
102