securitydept_utils/
ser.rs1use std::borrow::Cow;
2
3use serde::Deserialize;
4use serde_with::DeserializeAs;
5
6pub struct CommaOrSpaceSeparated<T>(std::marker::PhantomData<T>);
10
11impl<'de, T> DeserializeAs<'de, Vec<T>> for CommaOrSpaceSeparated<T>
12where
13 T: serde::de::DeserializeOwned,
14{
15 fn deserialize_as<D>(deserializer: D) -> std::result::Result<Vec<T>, D::Error>
16 where
17 D: serde::Deserializer<'de>,
18 {
19 let s = String::deserialize(deserializer)?;
20 s.split(|c: char| c == ',' || c.is_whitespace())
21 .map(str::trim)
22 .filter(|s| !s.is_empty())
23 .map(try_parse_maybe_json_string::<T, D>)
24 .collect()
25 }
26}
27
28pub struct SpaceSeparated<T>(std::marker::PhantomData<T>);
29
30impl<'de, T> DeserializeAs<'de, Vec<T>> for SpaceSeparated<T>
31where
32 T: serde::de::DeserializeOwned,
33{
34 fn deserialize_as<D>(deserializer: D) -> std::result::Result<Vec<T>, D::Error>
35 where
36 D: serde::Deserializer<'de>,
37 {
38 let s = String::deserialize(deserializer)?;
39 s.split_whitespace()
40 .map(str::trim)
41 .filter(|s| !s.is_empty())
42 .map(try_parse_maybe_json_string::<T, D>)
43 .collect()
44 }
45}
46
47fn try_parse_maybe_json_string<'de, T, D>(s: &str) -> std::result::Result<T, D::Error>
48where
49 T: serde::de::DeserializeOwned,
50 D: serde::Deserializer<'de>,
51{
52 let quoted = if s.starts_with('"') && s.ends_with('"') {
53 Cow::Borrowed(s)
54 } else {
55 Cow::Owned(serde_json::to_string(s).map_err(<D::Error as serde::de::Error>::custom)?)
56 };
57 serde_json::from_str::<T>(quoted.as_ref()).map_err(<D::Error as serde::de::Error>::custom)
58}