1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use serde::{Deserialize, Serialize};
5
6use super::util::TryFromStringVisitor;
7
8#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
22pub struct Bool<const D: bool = false>(pub bool);
23
24impl<const D: bool> Bool<D> {
25 pub const YES: Self = Bool(true);
27
28 pub const NO: Self = Bool(false);
30
31 pub const fn yes() -> Self {
33 Self::YES
34 }
35
36 pub const fn no() -> Self {
38 Self::NO
39 }
40
41 pub const fn as_str(&self) -> &'static str {
43 if self.0 {
44 "yes"
45 } else {
46 "no"
47 }
48 }
49}
50
51impl<const D: bool> Default for Bool<D> {
52 fn default() -> Self {
54 Self(D)
55 }
56}
57
58impl<const D: bool> From<bool> for Bool<D> {
59 fn from(value: bool) -> Self {
60 Self(value)
61 }
62}
63
64impl<const D: bool> From<Bool<D>> for bool {
65 fn from(value: Bool<D>) -> Self {
66 value.0
67 }
68}
69
70impl<const D: bool> From<Bool<D>> for &'static str {
71 fn from(value: Bool<D>) -> Self {
72 value.as_str()
73 }
74}
75
76impl<const D: bool> FromStr for Bool<D> {
77 type Err = &'static str;
78
79 fn from_str(s: &str) -> Result<Self, Self::Err> {
81 match s {
82 "yes" => Ok(Self::YES),
83 "no" => Ok(Self::NO),
84 _ => Err("expected \"yes\" or \"no\""),
85 }
86 }
87}
88
89impl<const D: bool> TryFrom<&str> for Bool<D> {
90 type Error = <Self as FromStr>::Err;
91
92 fn try_from(value: &str) -> Result<Self, Self::Error> {
93 value.parse()
94 }
95}
96
97impl<const D: bool> TryFrom<String> for Bool<D> {
98 type Error = <Self as FromStr>::Err;
99
100 fn try_from(value: String) -> Result<Self, Self::Error> {
101 value.parse()
102 }
103}
104
105impl<const D: bool> Display for Bool<D> {
106 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{}", self.as_str())
108 }
109}
110
111impl<const D: bool> Serialize for Bool<D> {
112 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
115 if self.0 != D {
116 serializer.collect_str(self)
117 } else {
118 serializer.serialize_none()
119 }
120 }
121}
122
123impl<'de, const DEFAULT: bool> Deserialize<'de> for Bool<DEFAULT> {
124 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
127 struct Visitor<const DEFAULT: bool>;
128
129 impl<'de, const DEFAULT: bool> serde::de::Visitor<'de> for Visitor<DEFAULT> {
130 type Value = Bool<DEFAULT>;
131
132 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
133 formatter.write_str("yes or no, or nothing")
134 }
135
136 #[inline]
137 fn visit_none<E: serde::de::Error>(self) -> Result<Self::Value, E> {
138 Ok(Bool::default())
139 }
140
141 #[inline]
142 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
143 where
144 D: serde::Deserializer<'de>,
145 {
146 deserializer.deserialize_str(TryFromStringVisitor::new())
147 }
148
149 #[inline]
150 fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> {
151 Ok(Bool::default())
152 }
153 }
154
155 deserializer.deserialize_option(Visitor::<DEFAULT>)
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use indoc::indoc;
162
163 use crate::test_util::serde_test;
164
165 use super::*;
166
167 type BoolDefaultFalse = Bool<false>;
168
169 #[test]
170 fn consts() {
171 assert_eq!(BoolDefaultFalse::YES, Bool(true));
172 assert_eq!(BoolDefaultFalse::NO, Bool(false));
173
174 assert_eq!(BoolDefaultFalse::YES, true.into());
175 assert_eq!(BoolDefaultFalse::NO, false.into());
176
177 assert_eq!(BoolDefaultFalse::yes(), BoolDefaultFalse::YES);
178 assert_eq!(BoolDefaultFalse::no(), BoolDefaultFalse::NO);
179 }
180
181 #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
182 struct Test {
183 foo: Bool<false>,
184 bar: Bool<true>,
185 }
186
187 serde_test! {
188 serde: {
189 indoc! {"
190 foo: yes
191 bar: no
192 "} => Test {
193 foo: Bool::YES,
194 bar: Bool::NO,
195 },
196 indoc! {"
197 foo: yes
198 "} => Test {
199 foo: Bool::YES,
200 bar: Bool::YES,
201 },
202 indoc! {"
203 bar: no
204 "} => Test {
205 foo: Bool::NO,
206 bar: Bool::NO,
207 },
208 "" => Test {
209 foo: Bool::NO,
210 bar: Bool::YES,
211 },
212 }
213 }
214}