1pub trait Deb822LikeParagraph: FromIterator<(String, String)> {
5 fn get(&self, key: &str) -> Option<String>;
7
8 fn set(&mut self, key: &str, value: &str);
10
11 fn remove(&mut self, key: &str);
13}
14
15impl Deb822LikeParagraph for crate::Paragraph {
16 fn get(&self, key: &str) -> Option<String> {
17 crate::Paragraph::get(self, key).map(|v| v.to_string())
18 }
19
20 fn set(&mut self, key: &str, value: &str) {
21 crate::Paragraph::set(self, key, value);
22 }
23
24 fn remove(&mut self, key: &str) {
25 crate::Paragraph::remove(self, key);
26 }
27}
28
29pub trait FromDeb822Paragraph<P: Deb822LikeParagraph> {
31 fn from_paragraph(paragraph: &P) -> Result<Self, String>
33 where
34 Self: Sized;
35}
36
37pub trait ToDeb822Paragraph<P: Deb822LikeParagraph> {
39 fn to_paragraph(&self) -> P;
41
42 fn update_paragraph(&self, paragraph: &mut P);
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn test_trait_impl_directly() {
52 let mut para = crate::Paragraph {
54 fields: vec![crate::Field {
55 name: "Test".to_string(),
56 value: "Value".to_string(),
57 }],
58 };
59
60 let result: Option<String> = Deb822LikeParagraph::get(¶, "Test");
62 assert_eq!(result, Some("Value".to_string()));
63
64 Deb822LikeParagraph::set(&mut para, "Test", "NewValue");
66 assert_eq!(para.get("Test"), Some("NewValue"));
67
68 Deb822LikeParagraph::remove(&mut para, "Test");
70 assert_eq!(para.get("Test"), None);
71 }
72
73 #[test]
74 fn test_deb822like_paragraph_impl() {
75 let mut para = crate::Paragraph {
77 fields: vec![crate::Field {
78 name: "Name".to_string(),
79 value: "Test".to_string(),
80 }],
81 };
82
83 assert_eq!(para.get("Name"), Some("Test"));
85 assert_eq!(para.get("NonExistent"), None);
86
87 para.set("Name", "NewValue");
89 assert_eq!(para.get("Name"), Some("NewValue"));
90
91 para.set("NewKey", "Value");
93 assert_eq!(para.get("NewKey"), Some("Value"));
94
95 para.remove("Name");
97 assert_eq!(para.get("Name"), None);
98 assert_eq!(para.get("NewKey"), Some("Value"));
99
100 let mut para = crate::Paragraph {
102 fields: vec![
103 crate::Field {
104 name: "Duplicate".to_string(),
105 value: "Value1".to_string(),
106 },
107 crate::Field {
108 name: "Duplicate".to_string(),
109 value: "Value2".to_string(),
110 },
111 ],
112 };
113
114 para.remove("Duplicate");
116 assert_eq!(para.get("Duplicate"), None);
117 assert_eq!(para.fields.len(), 0);
118 }
119
120 #[cfg(feature = "derive")]
121 mod derive {
122 use super::*;
123 use crate as deb822_fast;
124 use crate::{FromDeb822, ToDeb822};
125
126 #[test]
127 fn test_derive() {
128 #[derive(ToDeb822)]
129 struct Foo {
130 bar: String,
131 baz: i32,
132 blah: Option<String>,
133 }
134
135 let foo = Foo {
136 bar: "hello".to_string(),
137 baz: 42,
138 blah: None,
139 };
140
141 let paragraph: crate::Paragraph = foo.to_paragraph();
142 assert_eq!(paragraph.get("bar"), Some("hello"));
143 assert_eq!(paragraph.get("baz"), Some("42"));
144 assert_eq!(paragraph.get("blah"), None);
145 }
146
147 #[test]
148 fn test_optional_missing() {
149 #[derive(ToDeb822)]
150 struct Foo {
151 bar: String,
152 baz: Option<String>,
153 }
154
155 let foo = Foo {
156 bar: "hello".to_string(),
157 baz: None,
158 };
159
160 let paragraph: crate::Paragraph = foo.to_paragraph();
161 assert_eq!(paragraph.get("bar"), Some("hello"));
162 assert_eq!(paragraph.get("baz"), None);
163
164 assert_eq!("bar: hello\n", paragraph.to_string());
165 }
166
167 #[test]
168 fn test_deserialize_with() {
169 let mut para: crate::Paragraph = "bar: bar\n# comment\nbaz: blah\n".parse().unwrap();
170
171 fn to_bool(s: &str) -> Result<bool, String> {
172 Ok(s == "ja")
173 }
174
175 fn from_bool(s: &bool) -> String {
176 if *s {
177 "ja".to_string()
178 } else {
179 "nee".to_string()
180 }
181 }
182
183 #[derive(FromDeb822, ToDeb822)]
184 struct Foo {
185 bar: String,
186 #[deb822(deserialize_with = to_bool, serialize_with = from_bool)]
187 baz: bool,
188 }
189
190 let mut foo: Foo = Foo::from_paragraph(¶).unwrap();
191 assert_eq!(foo.bar, "bar");
192 assert!(!foo.baz);
193
194 foo.bar = "new".to_string();
195
196 foo.update_paragraph(&mut para);
197
198 assert_eq!(para.get("bar"), Some("new"));
199 assert_eq!(para.get("baz"), Some("nee"));
200 assert_eq!(para.to_string(), "bar: new\nbaz: nee\n");
201 }
202
203 #[test]
204 fn test_update_remove() {
205 let mut para: crate::Paragraph = "bar: bar\n# comment\nbaz: blah\n".parse().unwrap();
206
207 #[derive(FromDeb822, ToDeb822)]
208 struct Foo {
209 bar: Option<String>,
210 baz: String,
211 }
212
213 let mut foo: Foo = Foo::from_paragraph(¶).unwrap();
214 assert_eq!(foo.bar, Some("bar".to_string()));
215 assert_eq!(foo.baz, "blah");
216
217 foo.bar = None;
218
219 foo.update_paragraph(&mut para);
220
221 assert_eq!(para.get("bar"), None);
222 assert_eq!(para.get("baz"), Some("blah"));
223 assert_eq!(para.to_string(), "baz: blah\n");
224 }
225 }
226}