plex_api/media_container/preferences/
deserializer.rs1use super::Setting;
16use serde::{
17 de::{self, MapAccess, Visitor},
18 Deserialize, Deserializer,
19};
20use std::str::FromStr;
21use thiserror::Error;
22
23impl<'de> Deserialize<'de> for Setting {
24 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
25 where
26 D: Deserializer<'de>,
27 {
28 #[derive(Debug, Deserialize, Hash, PartialEq, Eq)]
29 #[serde(field_identifier, rename_all = "camelCase")]
30 enum Field {
31 Id,
32 Label,
33 Summary,
34 Hidden,
35 Advanced,
36 Group,
37 Value,
38 Default,
39 r#Type,
40 EnumValues,
41 }
42
43 struct SettingVisitor;
44 impl<'de> Visitor<'de> for SettingVisitor {
45 type Value = Setting;
46
47 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
48 formatter.write_str("struct Setting")
49 }
50
51 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
52 where
53 V: MapAccess<'de>,
54 {
55 let mut id = None;
56 let mut label = None;
57 let mut summary = None;
58 let mut hidden = None;
59 let mut advanced = None;
60 let mut group = None;
61 let mut value = None;
62 let mut default = None;
63 let mut r#type = None;
64 let mut enum_values: Option<serde_json::Value> = None;
65
66 while let Some(key) = map.next_key()? {
67 match key {
68 Field::Id => {
69 if id.is_some() {
70 return Err(de::Error::duplicate_field("id"));
71 }
72 id = Some(map.next_value()?);
73 }
74 Field::Label => {
75 if label.is_some() {
76 return Err(de::Error::duplicate_field("label"));
77 }
78 label = Some(map.next_value()?);
79 }
80 Field::Summary => {
81 if summary.is_some() {
82 return Err(de::Error::duplicate_field("summary"));
83 }
84 summary = Some(map.next_value()?);
85 }
86 Field::Hidden => {
87 if hidden.is_some() {
88 return Err(de::Error::duplicate_field("hidden"));
89 }
90 hidden = Some(map.next_value()?);
91 }
92 Field::Advanced => {
93 if advanced.is_some() {
94 return Err(de::Error::duplicate_field("advanced"));
95 }
96 advanced = Some(map.next_value()?);
97 }
98 Field::Group => {
99 if group.is_some() {
100 return Err(de::Error::duplicate_field("group"));
101 }
102 group = Some(map.next_value()?);
103 }
104 Field::Value => {
105 if value.is_some() {
106 return Err(de::Error::duplicate_field("value"));
107 }
108 value = Some(map.next_value()?);
109 }
110 Field::Default => {
111 if default.is_some() {
112 return Err(de::Error::duplicate_field("default"));
113 }
114 default = Some(map.next_value()?);
115 }
116 Field::Type => {
117 if r#type.is_some() {
118 return Err(de::Error::duplicate_field("type"));
119 }
120 r#type = Some(map.next_value()?);
121 }
122 Field::EnumValues => {
123 if enum_values.is_some() {
124 return Err(de::Error::duplicate_field("enumValues"));
125 }
126 enum_values = Some(map.next_value()?);
127 }
128 }
129 }
130
131 let id: String = id.ok_or_else(|| de::Error::missing_field("id"))?;
132 let label: String = label.ok_or_else(|| de::Error::missing_field("label"))?;
133 let summary: String = summary.ok_or_else(|| de::Error::missing_field("summary"))?;
134 let hidden: bool = hidden.ok_or_else(|| de::Error::missing_field("hidden"))?;
135 let advanced: bool =
136 advanced.ok_or_else(|| de::Error::missing_field("advanced"))?;
137 let group: String = group.ok_or_else(|| de::Error::missing_field("group"))?;
138 let r#type: String = r#type.ok_or_else(|| de::Error::missing_field("type"))?;
139 let value: serde_json::Value =
140 value.ok_or_else(|| de::Error::missing_field("value"))?;
141 let default: serde_json::Value =
142 default.ok_or_else(|| de::Error::missing_field("default"))?;
143
144 let mut suggested_values: Option<Vec<super::SettingEnumValue>> = None;
145
146 if let Some(serde_json::Value::String(enum_values)) = enum_values {
147 let suggested_values_tmp: Result<Vec<_>, _> = enum_values
148 .split('|')
149 .map(super::SettingEnumValue::from_str)
150 .collect();
151
152 if let Ok(ok) = suggested_values_tmp {
153 suggested_values = Some(ok);
154 } else {
155 return Err(de::Error::custom("invalid value inside enumValues"));
156 }
157 }
158
159 match r#type.as_str() {
160 "bool" => Ok(Setting {
161 id,
162 label,
163 summary,
164 hidden,
165 advanced,
166 group,
167 value: super::Value::Bool(
168 value
169 .as_bool()
170 .ok_or_else(|| de::Error::custom("bool expected"))?,
171 ),
172 default: super::Value::Bool(
173 default
174 .as_bool()
175 .ok_or_else(|| de::Error::custom("bool expected"))?,
176 ),
177 suggested_values,
178 }),
179 "int" => {
180 fn int_or_err<E>(v: serde_json::Value, id: &str) -> Result<i64, E>
181 where
182 E: de::Error,
183 {
184 match v {
185 serde_json::Value::Number(n) => n
186 .as_i64()
187 .ok_or_else(|| de::Error::custom(format_args!("invalid value for {id}: {n}, expected numeric or numeric string"))),
188
189 serde_json::Value::String(s) => s
190 .parse::<i64>()
191 .map_err(|_| de::Error::custom(format_args!("invalid value for {id}: \"{s}\", expected numeric or numeric string"))),
192
193 _ => Err(de::Error::custom(format_args!("invalid value for {id}: {v:?}, expected numeric or numeric string"))),
194 }
195 }
196
197 let value: i64 = int_or_err(value, &id)?;
198 let default: i64 = int_or_err(default, &id)?;
199
200 Ok(Setting {
201 id,
202 label,
203 summary,
204 hidden,
205 advanced,
206 group,
207 value: super::Value::Int(value),
208 default: super::Value::Int(default),
209 suggested_values,
210 })
211 }
212 "text" => Ok(Setting {
213 id,
214 label,
215 summary,
216 hidden,
217 advanced,
218 group,
219 value: super::Value::Text(
220 value
221 .as_str()
222 .ok_or_else(|| de::Error::custom("string expected"))?
223 .to_owned(),
224 ),
225 default: super::Value::Text(
226 default
227 .as_str()
228 .ok_or_else(|| de::Error::custom("string expected"))?
229 .to_owned(),
230 ),
231 suggested_values,
232 }),
233 "double" => {
234 fn double_or_err<E>(v: serde_json::Value, id: &str) -> Result<f64, E>
235 where
236 E: de::Error,
237 {
238 match v {
239 serde_json::Value::Number(n) => n
240 .as_f64()
241 .ok_or_else(|| de::Error::custom(format_args!("invalid value for {id}: {n}, expected numeric or numeric string"))),
242
243 serde_json::Value::String(s) => s
244 .parse::<f64>()
245 .map_err(|_| de::Error::custom(format_args!("invalid value for {id}: \"{s}\", expected numeric or numeric string"))),
246
247 _ => Err(de::Error::custom(format_args!("invalid value for {id}: {v:?}, expected numeric or numeric string"))),
248 }
249 }
250
251 let value: f64 = double_or_err(value, &id)?;
252 let default: f64 = double_or_err(default, &id)?;
253
254 Ok(Setting {
255 id,
256 label,
257 summary,
258 hidden,
259 advanced,
260 group,
261 value: super::Value::Double(value),
262 default: super::Value::Double(default),
263 suggested_values,
264 })
265 }
266 _ => Err(de::Error::unknown_variant(
267 &r#type,
268 &["bool", "int", "text", "double"],
269 )),
270 }
271 }
272 }
273
274 const FIELDS: &[&str] = &[
275 "id",
276 "label",
277 "summary",
278 "hidden",
279 "advanced",
280 "group",
281 "value",
282 "default",
283 "type",
284 "enumValues",
285 ];
286 deserializer.deserialize_struct("Setting", FIELDS, SettingVisitor)
287 }
288}
289
290#[derive(Error, Debug)]
291pub enum SettingError {
292 #[error("Provided `enumValues` string incorrectly formatted")]
293 IncorrectEnumValuesFormat,
294}
295
296impl std::str::FromStr for super::SettingEnumValue {
297 type Err = SettingError;
298
299 fn from_str(s: &str) -> Result<Self, Self::Err> {
300 let value: Vec<_> = s.split(':').collect();
301
302 match value.len() {
303 1 => Ok(super::SettingEnumValue {
304 value: String::from(s),
305 hint: String::from(s),
306 }),
307 2 => Ok(super::SettingEnumValue {
308 value: String::from(value[0]),
309 hint: String::from(value[1]),
310 }),
311 _ => Err(SettingError::IncorrectEnumValuesFormat),
312 }
313 }
314}