//! Deserializers for values that arrive as strings from the environment but //! may be native numbers/bools in a TOML file. use std::fmt; use std::marker::PhantomData; use std::str::FromStr; use serde::Deserializer; use serde::de::{self, Visitor}; struct Number(PhantomData); impl Visitor<'_> for Number { type Value = T; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("a number") } fn visit_str(self, v: &str) -> Result { v.trim() .parse() .map_err(|_| E::custom("expected a number in range")) } fn visit_u64(self, v: u64) -> Result { self.visit_str(&v.to_string()) } fn visit_i64(self, v: i64) -> Result { self.visit_str(&v.to_string()) } } pub fn number<'de, D, T>(d: D) -> Result where D: Deserializer<'de>, T: FromStr, { d.deserialize_any(Number(PhantomData)) } struct Flag { accepts_one: bool, } impl Visitor<'_> for Flag { type Value = bool; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("a boolean") } fn visit_bool(self, v: bool) -> Result { Ok(v) } fn visit_str(self, v: &str) -> Result { Ok(v == "true" || (self.accepts_one && v == "1")) } fn visit_u64(self, v: u64) -> Result { Ok(self.accepts_one && v == 1) } fn visit_i64(self, v: i64) -> Result { Ok(self.accepts_one && v == 1) } } /// `true` only for `true` or `1` (anything else is false, like the old readers). pub fn true_or_one<'de, D: Deserializer<'de>>(d: D) -> Result { d.deserialize_any(Flag { accepts_one: true }) } /// `true` only for `true`. pub fn true_only<'de, D: Deserializer<'de>>(d: D) -> Result { d.deserialize_any(Flag { accepts_one: false }) }