winget_types/installer/
install_modes.rs

1use std::{
2    fmt,
3    fmt::{Display, Formatter},
4};
5
6use bitflags::bitflags;
7use serde::{
8    Deserialize, Deserializer, Serialize, Serializer, de,
9    de::{SeqAccess, Visitor},
10    ser::SerializeSeq,
11};
12
13bitflags! {
14    /// A list of supported installer modes internally represented as bit flags
15    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
16    pub struct InstallModes: u8 {
17        const INTERACTIVE = 1;
18        const SILENT = 1 << 1;
19        const SILENT_WITH_PROGRESS = 1 << 2;
20    }
21}
22
23const INTERACTIVE: &str = "interactive";
24const SILENT: &str = "silent";
25const SILENT_WITH_PROGRESS: &str = "silentWithProgress";
26
27impl Display for InstallModes {
28    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29        match *self {
30            Self::INTERACTIVE => f.write_str("Interactive"),
31            Self::SILENT => f.write_str("Silent"),
32            Self::SILENT_WITH_PROGRESS => f.write_str("Silent with progress"),
33            _ => bitflags::parser::to_writer(self, f),
34        }
35    }
36}
37
38impl Serialize for InstallModes {
39    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
40    where
41        S: Serializer,
42    {
43        let mut seq = serializer.serialize_seq(Some(self.iter().count()))?;
44        for mode in self.iter() {
45            match mode {
46                Self::INTERACTIVE => seq.serialize_element(INTERACTIVE)?,
47                Self::SILENT => seq.serialize_element(SILENT)?,
48                Self::SILENT_WITH_PROGRESS => seq.serialize_element(SILENT_WITH_PROGRESS)?,
49                _ => {}
50            }
51        }
52        seq.end()
53    }
54}
55
56impl<'de> Deserialize<'de> for InstallModes {
57    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
58    where
59        D: Deserializer<'de>,
60    {
61        struct InstallModesVisitor;
62
63        impl<'de> Visitor<'de> for InstallModesVisitor {
64            type Value = InstallModes;
65
66            fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
67                formatter.write_str("a sequence of install mode strings")
68            }
69
70            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
71            where
72                V: SeqAccess<'de>,
73            {
74                let mut modes = InstallModes::empty();
75
76                while let Some(value) = seq.next_element::<&str>()? {
77                    match value {
78                        INTERACTIVE => modes |= InstallModes::INTERACTIVE,
79                        SILENT => modes |= InstallModes::SILENT,
80                        SILENT_WITH_PROGRESS => modes |= InstallModes::SILENT_WITH_PROGRESS,
81                        _ => {
82                            return Err(de::Error::unknown_variant(
83                                value,
84                                &[INTERACTIVE, SILENT, SILENT_WITH_PROGRESS],
85                            ));
86                        }
87                    }
88                }
89
90                Ok(modes)
91            }
92        }
93
94        deserializer.deserialize_seq(InstallModesVisitor)
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use indoc::indoc;
101    use rstest::rstest;
102
103    use crate::installer::install_modes::InstallModes;
104
105    #[rstest]
106    #[case(
107        InstallModes::all(),
108        indoc! {"
109            - interactive
110            - silent
111            - silentWithProgress
112        "}
113    )]
114    #[case(
115        InstallModes::empty(),
116        indoc! {"
117            []
118        "}
119    )]
120    #[case(
121        InstallModes::SILENT_WITH_PROGRESS | InstallModes::SILENT,
122        indoc! {"
123            - silent
124            - silentWithProgress
125        "}
126    )]
127    #[case(
128        InstallModes::INTERACTIVE,
129        indoc! {"
130            - interactive
131        "}
132    )]
133    fn serialize_install_modes(#[case] modes: InstallModes, #[case] expected: &str) {
134        assert_eq!(serde_yaml::to_string(&modes).unwrap(), expected);
135    }
136
137    #[rstest]
138    #[case(
139        indoc! {"
140            - interactive
141            - silent
142            - silentWithProgress
143        "},
144        InstallModes::all(),
145    )]
146    #[case(
147        indoc! {"
148            []
149        "},
150        InstallModes::empty()
151    )]
152    #[case(
153        indoc! {"
154            - silentWithProgress
155            - silent
156        "},
157        InstallModes::SILENT | InstallModes::SILENT_WITH_PROGRESS
158    )]
159    #[case(
160        indoc! {"
161            - interactive
162        "},
163        InstallModes::INTERACTIVE,
164    )]
165    fn deserialize_install_modes(#[case] input: &str, #[case] expected: InstallModes) {
166        assert_eq!(
167            serde_yaml::from_str::<InstallModes>(input).unwrap(),
168            expected
169        );
170    }
171
172    #[test]
173    fn install_modes_serialize_ordered() {
174        let input = indoc! {"
175            - silentWithProgress
176            - silent
177            - interactive
178        "};
179
180        let deserialized = serde_yaml::from_str::<InstallModes>(input).unwrap();
181
182        assert_eq!(
183            serde_yaml::to_string(&deserialized).unwrap(),
184            indoc! {"
185                - interactive
186                - silent
187                - silentWithProgress
188            "}
189        );
190    }
191}