oxsdatatypes/
boolean.rs

1use crate::{Decimal, Double, Float, Integer};
2use std::fmt;
3use std::str::{FromStr, ParseBoolError};
4
5/// [XML Schema `boolean` datatype](https://www.w3.org/TR/xmlschema11-2/#boolean)
6///
7/// Uses internally a [`bool`].
8#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
9#[repr(transparent)]
10pub struct Boolean {
11    value: bool,
12}
13
14impl Boolean {
15    /// Checks if the two values are [identical](https://www.w3.org/TR/xmlschema11-2/#identity).
16    #[inline]
17    #[must_use]
18    pub fn is_identical_with(self, other: Self) -> bool {
19        self == other
20    }
21}
22
23impl From<bool> for Boolean {
24    #[inline]
25    fn from(value: bool) -> Self {
26        Self { value }
27    }
28}
29
30impl From<Integer> for Boolean {
31    #[inline]
32    fn from(value: Integer) -> Self {
33        (value != Integer::from(0)).into()
34    }
35}
36
37impl From<Decimal> for Boolean {
38    #[inline]
39    fn from(value: Decimal) -> Self {
40        (value != Decimal::from(0)).into()
41    }
42}
43
44impl From<Float> for Boolean {
45    #[inline]
46    fn from(value: Float) -> Self {
47        (value != Float::from(0.) && !value.is_nan()).into()
48    }
49}
50
51impl From<Double> for Boolean {
52    #[inline]
53    fn from(value: Double) -> Self {
54        (value != Double::from(0.) && !value.is_nan()).into()
55    }
56}
57
58impl From<Boolean> for bool {
59    #[inline]
60    fn from(value: Boolean) -> Self {
61        value.value
62    }
63}
64
65impl FromStr for Boolean {
66    type Err = ParseBoolError;
67
68    #[inline]
69    fn from_str(input: &str) -> Result<Self, Self::Err> {
70        Ok(match input {
71            "true" | "1" => true,
72            "false" | "0" => false,
73            _ => bool::from_str(input)?,
74        }
75        .into())
76    }
77}
78
79impl fmt::Display for Boolean {
80    #[inline]
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        self.value.fmt(f)
83    }
84}
85
86#[cfg(test)]
87#[allow(clippy::panic_in_result_fn)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn from_str() -> Result<(), ParseBoolError> {
93        assert_eq!(Boolean::from_str("true")?.to_string(), "true");
94        assert_eq!(Boolean::from_str("1")?.to_string(), "true");
95        assert_eq!(Boolean::from_str("false")?.to_string(), "false");
96        assert_eq!(Boolean::from_str("0")?.to_string(), "false");
97        Ok(())
98    }
99
100    #[test]
101    fn from_integer() {
102        assert_eq!(Boolean::from(false), Integer::from(0).into());
103        assert_eq!(Boolean::from(true), Integer::from(1).into());
104        assert_eq!(Boolean::from(true), Integer::from(2).into());
105    }
106
107    #[test]
108    fn from_decimal() {
109        assert_eq!(Boolean::from(false), Decimal::from(0).into());
110        assert_eq!(Boolean::from(true), Decimal::from(1).into());
111        assert_eq!(Boolean::from(true), Decimal::from(2).into());
112    }
113
114    #[test]
115    fn from_float() {
116        assert_eq!(Boolean::from(false), Float::from(0.).into());
117        assert_eq!(Boolean::from(true), Float::from(1.).into());
118        assert_eq!(Boolean::from(true), Float::from(2.).into());
119        assert_eq!(Boolean::from(false), Float::from(f32::NAN).into());
120        assert_eq!(Boolean::from(true), Float::from(f32::INFINITY).into());
121    }
122
123    #[test]
124    fn from_double() {
125        assert_eq!(Boolean::from(false), Double::from(0.).into());
126        assert_eq!(Boolean::from(true), Double::from(1.).into());
127        assert_eq!(Boolean::from(true), Double::from(2.).into());
128        assert_eq!(Boolean::from(false), Double::from(f64::NAN).into());
129        assert_eq!(Boolean::from(true), Double::from(f64::INFINITY).into());
130    }
131}