use serde::de::{Error, Visitor};
use serde::Deserializer;
use std::fmt::Formatter;
pub fn string_or_bool<'de, D: Deserializer<'de>>(deserializer: D) -> Result<bool, D::Error> {
deserializer.deserialize_any(StringOrBool)
}
pub fn string_or_bool_option<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<bool>, D::Error> {
deserializer.deserialize_option(StringOrBoolOption)
}
struct StringOrBool;
impl<'de> Visitor<'de> for StringOrBool {
type Value = bool;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("YAML boolean")
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
match v.to_lowercase().as_str() {
"true" | "yes" | "on" | "y" => Ok(true),
"false" | "no" | "off" | "n" => Ok(false),
_ => Err(Error::unknown_variant(
v,
&["true", "false", "yes", "no", "on", "off", "y", "n"],
)),
}
}
}
struct StringOrBoolOption;
impl<'de> Visitor<'de> for StringOrBoolOption {
type Value = Option<bool>;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("YAML boolean or null")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
string_or_bool(deserializer).map(Some)
}
}