serde_bool/
lib.rs

1//! Single value, true or false, boolean deserializers.
2//!
3//! # Examples
4//!
5//! Supporting serde untagged enums where only one boolean value is valid, allowing fallthrough to
6//! the next variant. Avoids need to wrap all fields in `Option<_>` just in case feature is disabled.
7//!
8//! ```
9//! #[derive(Debug, serde::Deserialize)]
10//! struct Config {
11//!     feature: FeatureConfig,
12//! }
13//!
14//! #[derive(Debug, serde::Deserialize)]
15//! #[serde(untagged)]
16//! enum FeatureConfig {
17//!     Disabled {
18//!         enabled: serde_bool::False
19//!     },
20//!
21//!     Enabled {
22//!         #[serde(default)]
23//!         enabled: serde_bool::True,
24//!         key: String,
25//!         secret: String,
26//!     }
27//! }
28//!
29//! // disabled variant is matched
30//! let config = toml::from_str::<Config>(r#"
31//!     [feature]
32//!     enabled = false
33//! "#).unwrap();
34//! assert!(matches!(config.feature, FeatureConfig::Disabled { .. }));
35//!
36//! // if the type used `enabled: bool`, this would cause issues and require Option<_> wrappers plus
37//! // further validation... instead an error is returned immediately regarding the missing fields
38//! let config = toml::from_str::<Config>(r#"
39//!     [feature]
40//!     enabled = true
41//! "#).unwrap_err();
42//!
43//! // using a `#[serde(default)]` annotation makes `enabled = true` optional here
44//! let config = toml::from_str::<Config>(r#"
45//!     [feature]
46//!     key = "foo"
47//!     secret = "bar"
48//! "#).unwrap();
49//! assert!(matches!(config.feature, FeatureConfig::Enabled { .. }));
50//!
51//! // extra keys can exists in the disabled case, but as usual will not be captured
52//! let config = toml::from_str::<Config>(r#"
53//!     [feature]
54//!     enabled = false
55//!     key = "foo"
56//!     secret = "bar"
57//! "#).unwrap();
58//! assert!(matches!(config.feature, FeatureConfig::Disabled { .. }));
59//! ```
60
61#![no_std]
62#![cfg_attr(docsrs, feature(doc_auto_cfg))]
63
64use serde::{Deserialize, Deserializer, Serialize, Serializer};
65
66/// Type that only deserializes from the `true` boolean value.
67///
68/// # Examples
69///
70/// ```
71/// assert_eq!(
72///     serde_json::from_str::<serde_bool::True>("true").unwrap().as_bool(),
73///     true,
74/// );
75///
76/// serde_json::from_str::<serde_bool::True>("false").unwrap_err();
77/// serde_json::from_str::<serde_bool::True>("42").unwrap_err();
78/// ```
79#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
80pub struct True;
81
82impl True {
83    /// Returns `true`.
84    pub const fn as_bool(self) -> bool {
85        true
86    }
87}
88
89impl From<True> for bool {
90    fn from(_: True) -> Self {
91        true
92    }
93}
94
95impl PartialEq<False> for True {
96    fn eq(&self, _: &False) -> bool {
97        false
98    }
99}
100
101impl PartialEq<bool> for True {
102    fn eq(&self, other: &bool) -> bool {
103        self.as_bool() == *other
104    }
105}
106
107impl PartialEq<True> for bool {
108    fn eq(&self, other: &True) -> bool {
109        *self == other.as_bool()
110    }
111}
112
113impl<'de> Deserialize<'de> for True {
114    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
115        if bool::deserialize(deserializer)? {
116            Ok(Self)
117        } else {
118            Err(serde::de::Error::invalid_value(
119                serde::de::Unexpected::Bool(false),
120                &"the `true` boolean",
121            ))
122        }
123    }
124}
125
126impl Serialize for True {
127    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
128        serializer.serialize_bool(true)
129    }
130}
131
132/// Type that only deserializes from the `false` boolean value.
133///
134/// # Examples
135///
136/// ```
137/// assert_eq!(
138///     serde_json::from_str::<serde_bool::False>("false").unwrap().as_bool(),
139///     false,
140/// );
141///
142/// serde_json::from_str::<serde_bool::False>("true").unwrap_err();
143/// serde_json::from_str::<serde_bool::False>("42").unwrap_err();
144/// ```
145#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
146pub struct False;
147
148impl False {
149    /// Returns `false`.
150    pub const fn as_bool(self) -> bool {
151        false
152    }
153}
154
155impl From<False> for bool {
156    fn from(_: False) -> Self {
157        false
158    }
159}
160
161impl PartialEq<True> for False {
162    fn eq(&self, _: &True) -> bool {
163        false
164    }
165}
166
167impl PartialEq<bool> for False {
168    fn eq(&self, other: &bool) -> bool {
169        self.as_bool() == *other
170    }
171}
172
173impl PartialEq<False> for bool {
174    fn eq(&self, other: &False) -> bool {
175        *self == other.as_bool()
176    }
177}
178
179impl<'de> Deserialize<'de> for False {
180    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
181        if bool::deserialize(deserializer)? {
182            Err(serde::de::Error::invalid_value(
183                serde::de::Unexpected::Bool(true),
184                &"the `false` boolean",
185            ))
186        } else {
187            Ok(Self)
188        }
189    }
190}
191
192impl Serialize for False {
193    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
194        serializer.serialize_bool(false)
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201
202    #[derive(Debug, Deserialize, PartialEq)]
203    struct Tru {
204        foo: True,
205    }
206
207    #[test]
208    fn de_true() {
209        assert_eq!(
210            Tru { foo: True },
211            serde_json::from_str::<Tru>(r#"{"foo": true}"#).unwrap(),
212        );
213
214        serde_json::from_str::<Tru>(r#"{"foo": false}"#).unwrap_err();
215        serde_json::from_str::<Tru>(r#"{"foo": 42}"#).unwrap_err();
216    }
217
218    #[derive(Debug, Deserialize, PartialEq)]
219    struct Fal {
220        foo: False,
221    }
222
223    #[test]
224    fn de_false() {
225        assert_eq!(
226            Fal { foo: False },
227            serde_json::from_str::<Fal>(r#"{"foo": false}"#).unwrap(),
228        );
229
230        serde_json::from_str::<Fal>(r#"{"foo": true}"#).unwrap_err();
231        serde_json::from_str::<Fal>(r#"{"foo": 42}"#).unwrap_err();
232    }
233
234    #[test]
235    fn ser() {
236        assert_eq!("true", serde_json::to_string(&True).unwrap());
237        assert_eq!("false", serde_json::to_string(&False).unwrap());
238    }
239
240    #[test]
241    fn as_bool() {
242        assert!(True.as_bool());
243        assert!(!False.as_bool());
244    }
245
246    #[test]
247    fn from() {
248        assert!(bool::from(True));
249        assert!(!bool::from(False));
250    }
251
252    #[test]
253    fn eq() {
254        assert_eq!(True, True);
255        assert_eq!(True, true);
256        assert_eq!(true, True);
257        assert_eq!(False, False);
258        assert_eq!(False, false);
259        assert_eq!(false, False);
260
261        assert_ne!(True, False);
262        assert_ne!(True, false);
263        assert_ne!(False, True);
264        assert_ne!(false, True);
265
266        assert_ne!(False, True);
267        assert_ne!(False, true);
268        assert_ne!(True, False);
269        assert_ne!(true, False);
270    }
271
272    #[test]
273    fn formatting() {
274        let _ = format_args!("{:?}", True);
275        let _ = format_args!("{:?}", False);
276    }
277
278    #[test]
279    fn other_implementations() {
280        #![allow(clippy::default_constructed_unit_structs)]
281
282        assert_eq!(True.clone(), True);
283        assert_eq!(False.clone(), False);
284
285        assert_eq!(True::default(), True);
286        assert_eq!(False::default(), False);
287    }
288}