opendal/raw/
serde_util.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::collections::hash_map::IntoIter;
19use std::collections::HashMap;
20use std::iter::empty;
21
22use serde::de::value::MapDeserializer;
23use serde::de::value::SeqDeserializer;
24use serde::de::Deserializer;
25use serde::de::IntoDeserializer;
26use serde::de::Visitor;
27use serde::de::{self};
28
29use crate::*;
30
31/// Parse xml deserialize error into opendal::Error.
32pub fn new_xml_deserialize_error(e: quick_xml::DeError) -> Error {
33    Error::new(ErrorKind::Unexpected, "deserialize xml").set_source(e)
34}
35
36/// Parse json serialize error into opendal::Error.
37pub fn new_json_serialize_error(e: serde_json::Error) -> Error {
38    Error::new(ErrorKind::Unexpected, "serialize json").set_source(e)
39}
40
41/// Parse json deserialize error into opendal::Error.
42pub fn new_json_deserialize_error(e: serde_json::Error) -> Error {
43    Error::new(ErrorKind::Unexpected, "deserialize json").set_source(e)
44}
45
46/// ConfigDeserializer is used to deserialize given configs from `HashMap<String, String>`.
47///
48/// This is only used by our services' config.
49pub struct ConfigDeserializer(MapDeserializer<'static, Pairs, de::value::Error>);
50
51impl ConfigDeserializer {
52    /// Create a new config deserializer.
53    pub fn new(map: HashMap<String, String>) -> Self {
54        let pairs = Pairs(map.into_iter());
55        Self(MapDeserializer::new(pairs))
56    }
57}
58
59impl<'de> Deserializer<'de> for ConfigDeserializer {
60    type Error = de::value::Error;
61
62    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
63    where
64        V: Visitor<'de>,
65    {
66        self.deserialize_map(visitor)
67    }
68
69    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
70    where
71        V: Visitor<'de>,
72    {
73        visitor.visit_map(self.0)
74    }
75
76    serde::forward_to_deserialize_any! {
77        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
78        bytes byte_buf unit_struct tuple_struct
79        identifier tuple ignored_any option newtype_struct enum
80        struct
81    }
82}
83
84/// Pairs is used to implement Iterator to meet the requirement of [`MapDeserializer`].
85struct Pairs(IntoIter<String, String>);
86
87impl Iterator for Pairs {
88    type Item = (String, Pair);
89
90    fn next(&mut self) -> Option<Self::Item> {
91        self.0.next().map(|(k, v)| (k.to_lowercase(), Pair(k, v)))
92    }
93}
94
95/// Pair is used to hold both key and value of a config for better error output.
96struct Pair(String, String);
97
98impl IntoDeserializer<'_, de::value::Error> for Pair {
99    type Deserializer = Self;
100
101    fn into_deserializer(self) -> Self::Deserializer {
102        self
103    }
104}
105
106impl<'de> Deserializer<'de> for Pair {
107    type Error = de::value::Error;
108
109    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
110    where
111        V: Visitor<'de>,
112    {
113        self.1.into_deserializer().deserialize_any(visitor)
114    }
115
116    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
117    where
118        V: Visitor<'de>,
119    {
120        match self.1.to_lowercase().as_str() {
121            "true" | "on" => true.into_deserializer().deserialize_bool(visitor),
122            "false" | "off" => false.into_deserializer().deserialize_bool(visitor),
123            _ => Err(de::Error::custom(format_args!(
124                "parse config '{}' with value '{}' failed for {:?}",
125                self.0, self.1, "invalid bool value"
126            ))),
127        }
128    }
129
130    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
131    where
132        V: Visitor<'de>,
133    {
134        match self.1.parse::<i8>() {
135            Ok(val) => val.into_deserializer().deserialize_i8(visitor),
136            Err(e) => Err(de::Error::custom(format_args!(
137                "parse config '{}' with value '{}' failed for {:?}",
138                self.0, self.1, e
139            ))),
140        }
141    }
142
143    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
144    where
145        V: Visitor<'de>,
146    {
147        match self.1.parse::<i16>() {
148            Ok(val) => val.into_deserializer().deserialize_i16(visitor),
149            Err(e) => Err(de::Error::custom(format_args!(
150                "parse config '{}' with value '{}' failed for {:?}",
151                self.0, self.1, e
152            ))),
153        }
154    }
155
156    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
157    where
158        V: Visitor<'de>,
159    {
160        match self.1.parse::<i32>() {
161            Ok(val) => val.into_deserializer().deserialize_i32(visitor),
162            Err(e) => Err(de::Error::custom(format_args!(
163                "parse config '{}' with value '{}' failed for {:?}",
164                self.0, self.1, e
165            ))),
166        }
167    }
168
169    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
170    where
171        V: Visitor<'de>,
172    {
173        match self.1.parse::<i64>() {
174            Ok(val) => val.into_deserializer().deserialize_i64(visitor),
175            Err(e) => Err(de::Error::custom(format_args!(
176                "parse config '{}' with value '{}' failed for {:?}",
177                self.0, self.1, e
178            ))),
179        }
180    }
181
182    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
183    where
184        V: Visitor<'de>,
185    {
186        match self.1.parse::<u8>() {
187            Ok(val) => val.into_deserializer().deserialize_u8(visitor),
188            Err(e) => Err(de::Error::custom(format_args!(
189                "parse config '{}' with value '{}' failed for {:?}",
190                self.0, self.1, e
191            ))),
192        }
193    }
194
195    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
196    where
197        V: Visitor<'de>,
198    {
199        match self.1.parse::<u16>() {
200            Ok(val) => val.into_deserializer().deserialize_u16(visitor),
201            Err(e) => Err(de::Error::custom(format_args!(
202                "parse config '{}' with value '{}' failed for {:?}",
203                self.0, self.1, e
204            ))),
205        }
206    }
207
208    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
209    where
210        V: Visitor<'de>,
211    {
212        match self.1.parse::<u32>() {
213            Ok(val) => val.into_deserializer().deserialize_u32(visitor),
214            Err(e) => Err(de::Error::custom(format_args!(
215                "parse config '{}' with value '{}' failed for {:?}",
216                self.0, self.1, e
217            ))),
218        }
219    }
220
221    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
222    where
223        V: Visitor<'de>,
224    {
225        match self.1.parse::<u64>() {
226            Ok(val) => val.into_deserializer().deserialize_u64(visitor),
227            Err(e) => Err(de::Error::custom(format_args!(
228                "parse config '{}' with value '{}' failed for {:?}",
229                self.0, self.1, e
230            ))),
231        }
232    }
233
234    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
235    where
236        V: Visitor<'de>,
237    {
238        match self.1.parse::<f32>() {
239            Ok(val) => val.into_deserializer().deserialize_f32(visitor),
240            Err(e) => Err(de::Error::custom(format_args!(
241                "parse config '{}' with value '{}' failed for {:?}",
242                self.0, self.1, e
243            ))),
244        }
245    }
246
247    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
248    where
249        V: Visitor<'de>,
250    {
251        match self.1.parse::<f64>() {
252            Ok(val) => val.into_deserializer().deserialize_f64(visitor),
253            Err(e) => Err(de::Error::custom(format_args!(
254                "parse config '{}' with value '{}' failed for {:?}",
255                self.0, self.1, e
256            ))),
257        }
258    }
259
260    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
261    where
262        V: Visitor<'de>,
263    {
264        if self.1.is_empty() {
265            visitor.visit_none()
266        } else {
267            visitor.visit_some(self)
268        }
269    }
270
271    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
272    where
273        V: Visitor<'de>,
274    {
275        // Return empty instead of `[""]`.
276        if self.1.is_empty() {
277            SeqDeserializer::new(empty::<Pair>())
278                .deserialize_seq(visitor)
279                .map_err(|e| {
280                    de::Error::custom(format_args!(
281                        "parse config '{}' with value '{}' failed for {:?}",
282                        self.0, self.1, e
283                    ))
284                })
285        } else {
286            let values = self
287                .1
288                .split(',')
289                .map(|v| Pair(self.0.clone(), v.trim().to_owned()));
290            SeqDeserializer::new(values)
291                .deserialize_seq(visitor)
292                .map_err(|e| {
293                    de::Error::custom(format_args!(
294                        "parse config '{}' with value '{}' failed for {:?}",
295                        self.0, self.1, e
296                    ))
297                })
298        }
299    }
300
301    serde::forward_to_deserialize_any! {
302        char str string unit newtype_struct enum
303        bytes byte_buf map unit_struct tuple_struct
304        identifier tuple ignored_any
305        struct
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use serde::Deserialize;
312
313    use super::*;
314
315    #[derive(Debug, Default, Deserialize, Eq, PartialEq)]
316    #[serde(default)]
317    #[non_exhaustive]
318    pub struct TestConfig {
319        bool_value: bool,
320        bool_option_value_none: Option<bool>,
321        bool_option_value_some: Option<bool>,
322        bool_value_with_on: bool,
323        bool_value_with_off: bool,
324
325        string_value: String,
326        string_option_value_none: Option<String>,
327        string_option_value_some: Option<String>,
328
329        u8_value: u8,
330        u16_value: u16,
331        u32_value: u32,
332        u64_value: u64,
333        i8_value: i8,
334        i16_value: i16,
335        i32_value: i32,
336        i64_value: i64,
337
338        vec_value: Vec<String>,
339        vec_value_two: Vec<String>,
340        vec_none: Option<Vec<String>>,
341        vec_empty: Vec<String>,
342    }
343
344    #[test]
345    fn test_config_deserializer() {
346        let mut map = HashMap::new();
347        map.insert("bool_value", "true");
348        map.insert("bool_option_value_none", "");
349        map.insert("bool_option_value_some", "false");
350        map.insert("bool_value_with_on", "on");
351        map.insert("bool_value_with_off", "off");
352        map.insert("string_value", "hello");
353        map.insert("string_option_value_none", "");
354        map.insert("string_option_value_some", "hello");
355        map.insert("u8_value", "8");
356        map.insert("u16_value", "16");
357        map.insert("u32_value", "32");
358        map.insert("u64_value", "64");
359        map.insert("i8_value", "-8");
360        map.insert("i16_value", "16");
361        map.insert("i32_value", "-32");
362        map.insert("i64_value", "64");
363        map.insert("vec_value", "hello");
364        map.insert("vec_value_two", "hello,world");
365        map.insert("vec_none", "");
366        map.insert("vec_empty", "");
367        let map = map
368            .into_iter()
369            .map(|(k, v)| (k.to_string(), v.to_string()))
370            .collect();
371
372        let output = TestConfig::deserialize(ConfigDeserializer::new(map)).unwrap();
373        assert_eq!(
374            output,
375            TestConfig {
376                bool_value: true,
377                bool_option_value_none: None,
378                bool_option_value_some: Some(false),
379                bool_value_with_on: true,
380                bool_value_with_off: false,
381                string_value: "hello".to_string(),
382                string_option_value_none: None,
383                string_option_value_some: Some("hello".to_string()),
384                u8_value: 8,
385                u16_value: 16,
386                u32_value: 32,
387                u64_value: 64,
388                i8_value: -8,
389                i16_value: 16,
390                i32_value: -32,
391                i64_value: 64,
392                vec_value: vec!["hello".to_string()],
393                vec_value_two: vec!["hello".to_string(), "world".to_string()],
394                vec_none: None,
395                vec_empty: vec![],
396            }
397        );
398    }
399
400    #[test]
401    fn test_part_config_deserializer() {
402        let mut map = HashMap::new();
403        map.insert("bool_value", "true");
404        let map = map
405            .into_iter()
406            .map(|(k, v)| (k.to_string(), v.to_string()))
407            .collect();
408
409        let output = TestConfig::deserialize(ConfigDeserializer::new(map)).unwrap();
410        assert_eq!(
411            output,
412            TestConfig {
413                bool_value: true,
414                ..TestConfig::default()
415            }
416        );
417    }
418}