saluki_common/
deser.rs

1//! Deserialization helpers.
2//!
3//! This module provides various helpers for handling the deserialization of common data types in more flexible and
4//! permissive ways. These helpers are designed to be used with the `serde_with` crate.
5
6use std::fmt;
7
8use serde::{
9    de::{Error, Unexpected},
10    Deserializer,
11};
12use serde_with::DeserializeAs;
13
14/// Permissively deserializes a boolean.
15///
16/// This helper module allows deserializing a `bool` from a number of possible data types:
17///
18/// - `true` or `false` as a native boolean
19/// - `"true"` or `"false"` as a string (case insensitive)
20/// - `1` or `0` as an integer (signed, unsigned, or floating point)
21pub struct PermissiveBool;
22
23impl<'de> DeserializeAs<'de, bool> for PermissiveBool {
24    fn deserialize_as<D>(deserializer: D) -> Result<bool, D::Error>
25    where
26        D: Deserializer<'de>,
27    {
28        struct Visitor;
29
30        impl<'vde> serde::de::Visitor<'vde> for Visitor {
31            type Value = bool;
32
33            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
34                formatter.write_str("a boolean, string, integer, or floating-point number")
35            }
36
37            fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
38            where
39                E: Error,
40            {
41                Ok(value)
42            }
43
44            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
45            where
46                E: Error,
47            {
48                match value.to_lowercase().as_str() {
49                    "true" => Ok(true),
50                    "false" => Ok(false),
51                    _ => Err(Error::invalid_value(
52                        Unexpected::Str(value),
53                        &"\"true\" or \"false\" (case insensitive)",
54                    )),
55                }
56            }
57
58            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
59            where
60                E: Error,
61            {
62                match value {
63                    0 => Ok(false),
64                    1 => Ok(true),
65                    _ => Err(Error::invalid_value(Unexpected::Signed(value), &"0 or 1")),
66                }
67            }
68
69            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
70            where
71                E: Error,
72            {
73                match value {
74                    0 => Ok(false),
75                    1 => Ok(true),
76                    _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &"0 or 1")),
77                }
78            }
79
80            fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
81            where
82                E: Error,
83            {
84                match value {
85                    0.0 => Ok(false),
86                    1.0 => Ok(true),
87                    _ => Err(Error::invalid_value(Unexpected::Float(value), &"0.0 or 1.0")),
88                }
89            }
90        }
91
92        deserializer.deserialize_any(Visitor)
93    }
94}