serde_command_opts/
lib.rs

1/*
2 * Copyright 2020 fsyncd, Berlin, Germany.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! A crate for serializing command line options (structopt in reverse).
18
19use serde::ser::{
20    self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
21    SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
22};
23use snafu::Snafu;
24use std::fmt::Display;
25
26/// Errors emitted during the serialization process.
27#[derive(Debug, Snafu)]
28pub enum Error {
29    #[snafu(display("Failed to serialize object: {}", msg))]
30    SerializationError { msg: String },
31}
32
33impl serde::ser::Error for Error {
34    fn custom<T>(msg: T) -> Self
35    where
36        T: Display,
37    {
38        Self::SerializationError {
39            msg: msg.to_string(),
40        }
41    }
42}
43
44/// A serializer intended for converting objects into command options..
45pub struct Serializer {
46    /// Output list of arguments / options.
47    args: Vec<String>,
48    /// Mode to use for serializing boolean values.
49    boolean_type: BooleanType,
50}
51
52/// Mode to use for serializing boolean values.
53pub enum BooleanType {
54    /// True is true and False is false.
55    TrueFalse,
56    /// True is on and False is off.
57    OnOff,
58}
59
60impl Serializer {
61    /// Construct a new command options serializer using the specified mode for boolean values.
62    pub fn new(boolean_type: BooleanType) -> Self {
63        Self {
64            args: vec![],
65            boolean_type,
66        }
67    }
68
69    /// Serialize an object into command options.
70    pub fn into_args<T>(mut self, value: &T) -> Result<Vec<String>, Error>
71    where
72        T: Serialize,
73    {
74        value.serialize(&mut self)?;
75        Ok(self.args)
76    }
77}
78
79/// Serialize an object into command options, using the default serializer settings.
80pub fn to_args<T>(value: &T) -> Result<Vec<String>, Error>
81where
82    T: Serialize,
83{
84    Serializer::new(BooleanType::TrueFalse).into_args(value)
85}
86
87impl<'a> ser::Serializer for &'a mut Serializer {
88    type Ok = ();
89    type Error = Error;
90    type SerializeSeq = Self;
91    type SerializeTuple = Self;
92    type SerializeTupleStruct = Self;
93    type SerializeTupleVariant = Self;
94    type SerializeMap = Self;
95    type SerializeStruct = Self;
96    type SerializeStructVariant = Self;
97
98    fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
99        self.args.push(
100            match self.boolean_type {
101                BooleanType::TrueFalse => {
102                    if v {
103                        "true"
104                    } else {
105                        "false"
106                    }
107                }
108                BooleanType::OnOff => {
109                    if v {
110                        "on"
111                    } else {
112                        "off"
113                    }
114                }
115            }
116            .into(),
117        );
118        Ok(())
119    }
120
121    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
122        self.serialize_i64(i64::from(v))
123    }
124
125    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
126        self.serialize_i64(i64::from(v))
127    }
128
129    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
130        self.serialize_i64(i64::from(v))
131    }
132
133    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
134        self.args.push(v.to_string());
135        Ok(())
136    }
137
138    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
139        self.serialize_u64(u64::from(v))
140    }
141
142    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
143        self.serialize_u64(u64::from(v))
144    }
145
146    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
147        self.serialize_u64(u64::from(v))
148    }
149
150    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
151        self.args.push(v.to_string());
152        Ok(())
153    }
154
155    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
156        self.serialize_f64(f64::from(v))
157    }
158
159    fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
160        self.args.push(v.to_string());
161        Ok(())
162    }
163
164    fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
165        self.serialize_str(&v.to_string())
166    }
167
168    fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
169        self.args.push(v.into());
170        Ok(())
171    }
172
173    fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
174        unimplemented!()
175    }
176
177    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
178        self.args.pop();
179        self.serialize_unit()
180    }
181
182    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
183    where
184        T: Serialize,
185    {
186        value.serialize(self)
187    }
188
189    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
190        // NOP
191        Ok(())
192    }
193
194    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
195        self.serialize_unit()
196    }
197
198    fn serialize_unit_variant(
199        self,
200        _name: &'static str,
201        _variant_index: u32,
202        variant: &'static str,
203    ) -> Result<Self::Ok, Self::Error> {
204        self.serialize_str(variant)
205    }
206
207    fn serialize_newtype_struct<T: ?Sized>(
208        self,
209        _name: &'static str,
210        value: &T,
211    ) -> Result<Self::Ok, Self::Error>
212    where
213        T: Serialize,
214    {
215        value.serialize(self)
216    }
217
218    fn serialize_newtype_variant<T: ?Sized>(
219        self,
220        _name: &'static str,
221        _variant_index: u32,
222        variant: &'static str,
223        value: &T,
224    ) -> Result<Self::Ok, Self::Error>
225    where
226        T: Serialize,
227    {
228        variant.serialize(&mut *self)?;
229        value.serialize(&mut *self)?;
230        Ok(())
231    }
232
233    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
234        self.args.pop();
235        Ok(self)
236    }
237
238    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
239        self.serialize_seq(Some(len))
240    }
241
242    fn serialize_tuple_struct(
243        self,
244        _name: &'static str,
245        len: usize,
246    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
247        self.serialize_seq(Some(len))
248    }
249
250    fn serialize_tuple_variant(
251        self,
252        _name: &'static str,
253        _variant_index: u32,
254        variant: &'static str,
255        _len: usize,
256    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
257        variant.serialize(&mut *self)?;
258        Ok(self)
259    }
260
261    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
262        Ok(self)
263    }
264
265    fn serialize_struct(
266        self,
267        _name: &'static str,
268        len: usize,
269    ) -> Result<Self::SerializeStruct, Self::Error> {
270        self.serialize_map(Some(len))
271    }
272
273    fn serialize_struct_variant(
274        self,
275        _name: &'static str,
276        _variant_index: u32,
277        variant: &'static str,
278        _len: usize,
279    ) -> Result<Self::SerializeStructVariant, Self::Error> {
280        variant.serialize(&mut *self)?;
281        Ok(self)
282    }
283
284    fn collect_str<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
285    where
286        T: Display,
287    {
288        unimplemented!()
289    }
290}
291
292impl<'a> SerializeSeq for &'a mut Serializer {
293    type Ok = ();
294    type Error = Error;
295
296    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
297    where
298        T: Serialize,
299    {
300        value.serialize(&mut **self)
301    }
302
303    fn end(self) -> Result<Self::Ok, Self::Error> {
304        Ok(())
305    }
306}
307
308impl<'a> SerializeTuple for &'a mut Serializer {
309    type Ok = ();
310    type Error = Error;
311
312    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
313    where
314        T: Serialize,
315    {
316        value.serialize(&mut **self)
317    }
318
319    fn end(self) -> Result<Self::Ok, Self::Error> {
320        Ok(())
321    }
322}
323
324impl<'a> SerializeTupleStruct for &'a mut Serializer {
325    type Ok = ();
326    type Error = Error;
327
328    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
329    where
330        T: Serialize,
331    {
332        value.serialize(&mut **self)
333    }
334
335    fn end(self) -> Result<Self::Ok, Self::Error> {
336        Ok(())
337    }
338}
339
340impl<'a> SerializeTupleVariant for &'a mut Serializer {
341    type Ok = ();
342    type Error = Error;
343
344    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
345    where
346        T: Serialize,
347    {
348        value.serialize(&mut **self)
349    }
350
351    fn end(self) -> Result<Self::Ok, Self::Error> {
352        Ok(())
353    }
354}
355
356impl<'a> SerializeMap for &'a mut Serializer {
357    type Ok = ();
358    type Error = Error;
359
360    fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
361    where
362        T: Serialize,
363    {
364        key.serialize(&mut **self)
365    }
366
367    fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
368    where
369        T: Serialize,
370    {
371        value.serialize(&mut **self)
372    }
373
374    fn end(self) -> Result<Self::Ok, Self::Error> {
375        Ok(())
376    }
377}
378
379impl<'a> SerializeStruct for &'a mut Serializer {
380    type Ok = ();
381    type Error = Error;
382
383    fn serialize_field<T: ?Sized>(
384        &mut self,
385        key: &'static str,
386        value: &T,
387    ) -> Result<(), Self::Error>
388    where
389        T: Serialize,
390    {
391        key.serialize(&mut **self)?;
392        value.serialize(&mut **self)
393    }
394
395    fn end(self) -> Result<Self::Ok, Self::Error> {
396        Ok(())
397    }
398}
399
400impl<'a> SerializeStructVariant for &'a mut Serializer {
401    type Ok = ();
402    type Error = Error;
403
404    fn serialize_field<T: ?Sized>(
405        &mut self,
406        key: &'static str,
407        value: &T,
408    ) -> Result<(), Self::Error>
409    where
410        T: Serialize,
411    {
412        key.serialize(&mut **self)?;
413        value.serialize(&mut **self)
414    }
415
416    fn end(self) -> Result<Self::Ok, Self::Error> {
417        Ok(())
418    }
419}
420
421#[cfg(test)]
422mod tests {
423    use super::*;
424    use maplit::hashmap;
425    use serde::Serialize;
426    use std::collections::HashMap;
427
428    #[test]
429    fn test_simple_struct() {
430        #[derive(Serialize)]
431        struct Test {
432            signed_int: i32,
433            unsigned_int: u32,
434            string: String,
435            character: char,
436        }
437
438        let options = to_args(&Test {
439            signed_int: -10,
440            unsigned_int: 10,
441            string: String::from("Hello World"),
442            character: 'X',
443        })
444        .unwrap();
445
446        let expected: Vec<String> = vec![
447            "signed_int".into(),
448            "-10".into(),
449            "unsigned_int".into(),
450            "10".into(),
451            "string".into(),
452            "Hello World".into(),
453            "character".into(),
454            "X".into(),
455        ];
456        assert_eq!(options, expected);
457    }
458
459    #[test]
460    fn test_nested_list() {
461        #[derive(Serialize)]
462        struct Test {
463            example: i32,
464            opts: Vec<String>,
465        }
466
467        let options = to_args(&Test {
468            example: 1,
469            opts: vec!["a".into(), "b".into(), "c".into()],
470        })
471        .unwrap();
472
473        let expected: Vec<String> = vec![
474            "example".into(),
475            "1".into(),
476            "a".into(),
477            "b".into(),
478            "c".into(),
479        ];
480        assert_eq!(options, expected);
481    }
482
483    #[test]
484    fn test_nested_map() {
485        #[derive(Serialize)]
486        struct Test {
487            example: i32,
488            fields: HashMap<String, i32>,
489        }
490
491        let options = to_args(&Test {
492            example: 1,
493            fields: hashmap! {
494                "a".into() => 1,
495                "b".into() => 2,
496            },
497        })
498        .unwrap();
499
500        let expected: Vec<String> = vec![
501            "example".into(),
502            "1".into(),
503            "fields".into(),
504            "a".into(),
505            "1".into(),
506            "b".into(),
507            "2".into(),
508        ];
509        assert_eq!(options, expected);
510    }
511
512    #[test]
513    fn test_boolean_modes() {
514        #[derive(Serialize)]
515        struct Test {
516            #[serde(rename = "my-feature")]
517            feature: bool,
518        }
519
520        let options = Serializer::new(BooleanType::OnOff)
521            .into_args(&Test { feature: true })
522            .unwrap();
523
524        let expected: Vec<String> = vec!["my-feature".into(), "on".into()];
525        assert_eq!(options, expected);
526    }
527
528    #[test]
529    fn test_optional_field() {
530        #[derive(Serialize)]
531        struct Test {
532            name: Option<String>,
533        }
534
535        let options = to_args(&Test {
536            name: Some("Alice".into()),
537        })
538        .unwrap();
539
540        let expected: Vec<String> = vec!["name".into(), "Alice".into()];
541        assert_eq!(options, expected);
542
543        let options = to_args(&Test { name: None }).unwrap();
544
545        let expected: Vec<String> = vec![];
546        assert_eq!(options, expected);
547    }
548}