teaql_core/
serde_utils.rs1use serde::{Deserialize, Deserializer, Serializer};
2
3pub mod trimmed_string {
4 use super::*;
5
6 pub fn serialize<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error>
7 where
8 S: Serializer,
9 {
10 serializer.serialize_str(value.trim())
11 }
12
13 pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
14 where
15 D: Deserializer<'de>,
16 {
17 let s = String::deserialize(deserializer)?;
18 Ok(s.trim().to_owned())
19 }
20}
21
22pub mod trimmed_opt_string {
23 use super::*;
24
25 pub fn serialize<S>(value: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: Serializer,
28 {
29 match value {
30 Some(v) => serializer.serialize_str(v.trim()),
31 None => serializer.serialize_none(),
32 }
33 }
34
35 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
36 where
37 D: Deserializer<'de>,
38 {
39 let opt = Option::<String>::deserialize(deserializer)?;
40 Ok(opt.map(|s| s.trim().to_owned()))
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use serde::{Deserialize, Serialize};
47
48 use super::{trimmed_opt_string, trimmed_string};
49
50 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
51 struct TrimmedFields {
52 #[serde(with = "trimmed_string")]
53 required: String,
54 #[serde(default, with = "trimmed_opt_string")]
55 optional: Option<String>,
56 }
57
58 #[test]
59 fn trimmed_string_helpers_trim_during_serialization() {
60 let fields = TrimmedFields {
61 required: " required value\n".to_owned(),
62 optional: Some("\toptional value ".to_owned()),
63 };
64
65 assert_eq!(
66 serde_json::to_value(fields).expect("trimmed fields should serialize"),
67 serde_json::json!({
68 "required": "required value",
69 "optional": "optional value"
70 })
71 );
72 }
73
74 #[test]
75 fn trimmed_optional_string_preserves_none_during_serialization() {
76 let fields = TrimmedFields {
77 required: " value ".to_owned(),
78 optional: None,
79 };
80
81 assert_eq!(
82 serde_json::to_value(fields).expect("trimmed fields should serialize"),
83 serde_json::json!({
84 "required": "value",
85 "optional": null
86 })
87 );
88 }
89
90 #[test]
91 fn trimmed_string_helpers_trim_during_deserialization() {
92 let fields: TrimmedFields = serde_json::from_value(serde_json::json!({
93 "required": " required value\n",
94 "optional": "\toptional value "
95 }))
96 .expect("trimmed fields should deserialize");
97
98 assert_eq!(
99 fields,
100 TrimmedFields {
101 required: "required value".to_owned(),
102 optional: Some("optional value".to_owned()),
103 }
104 );
105 }
106
107 #[test]
108 fn trimmed_optional_string_keeps_whitespace_only_input_as_some_empty() {
109 let fields: TrimmedFields = serde_json::from_value(serde_json::json!({
110 "required": " value ",
111 "optional": " \t\n "
112 }))
113 .expect("trimmed fields should deserialize");
114
115 assert_eq!(fields.required, "value");
116 assert_eq!(fields.optional, Some(String::new()));
117 }
118}