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