use std::{num::NonZeroU32, time::Duration};
use serde::{
de::{Deserializer, Error as SerdeDeError},
Deserialize,
};
use toml::value::Value;
pub(crate) fn into_bool<'de, D>(deserializer: D) -> std::result::Result<bool, D::Error>
where
D: Deserializer<'de>,
{
let value = match toml::value::Value::deserialize(deserializer)? {
Value::Boolean(b) => b,
Value::String(s) => s.parse::<bool>().map_err(SerdeDeError::custom)?,
_ => {
return Err(SerdeDeError::custom(
"must provide a boolean or string to convert to a boolean",
));
}
};
Ok(value)
}
pub(crate) fn into_option_bool<'de, D>(
deserializer: D,
) -> std::result::Result<Option<bool>, D::Error>
where
D: Deserializer<'de>,
{
let value = into_bool(deserializer)?;
Ok(Some(value))
}
pub(crate) fn into_option_duration_ms<'de, D>(
deserializer: D,
) -> std::result::Result<Option<Duration>, D::Error>
where
D: Deserializer<'de>,
{
let value = match toml::value::Value::deserialize(deserializer)? {
Value::Integer(i) => u64::try_from(i).map_err(SerdeDeError::custom)?,
Value::String(s) => s.parse::<u64>().map_err(SerdeDeError::custom)?,
_ => {
return Err(SerdeDeError::custom(
"must provide an integer or string to convert to a duration in milliseconds",
));
}
};
Ok(Some(Duration::from_millis(value)))
}
pub(crate) fn into_option_nonzero_u32<'de, D>(
deserializer: D,
) -> std::result::Result<Option<NonZeroU32>, D::Error>
where
D: Deserializer<'de>,
{
let value = match toml::value::Value::deserialize(deserializer)? {
Value::Integer(i) => {
let unsigned = u32::try_from(i).map_err(SerdeDeError::custom)?;
NonZeroU32::new(unsigned)
.ok_or_else(|| SerdeDeError::custom("must provide a positive integer"))?
}
Value::String(s) => s.parse::<NonZeroU32>().map_err(SerdeDeError::custom)?,
_ => {
return Err(SerdeDeError::custom(
"must provide an integer or string to convert to a duration",
));
}
};
Ok(Some(value))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn into_option_bool_from_string() {
let input = Value::String(String::from("true"));
let got = into_option_bool(input);
assert_eq!(got, Ok(Some(true)));
}
#[test]
fn into_option_bool_from_invalid_string() {
let input = Value::String(String::from("foo"));
let got = into_option_bool(input);
assert!(got.is_err());
}
#[test]
fn into_option_bool_from_bool() {
let input = Value::Boolean(true);
let got = into_option_bool(input);
assert_eq!(got, Ok(Some(true)));
}
#[test]
fn into_option_duration_ms_from_string() {
let input = Value::String(String::from("123"));
let got = into_option_duration_ms(input);
assert_eq!(got, Ok(Some(Duration::from_millis(123))));
}
#[test]
fn into_option_duration_ms_from_invalid_string() {
let input = Value::String(String::from("foo"));
let got = into_option_duration_ms(input);
assert!(got.is_err());
}
#[test]
fn into_option_duration_ms_from_i64() {
let input = Value::Integer(123);
let got = into_option_duration_ms(input);
assert_eq!(got, Ok(Some(Duration::from_millis(123))));
}
#[test]
fn into_option_nonzero_u32_from_string() {
let input = Value::String(String::from("123"));
let got = into_option_nonzero_u32(input);
assert_eq!(got, Ok(NonZeroU32::new(123)));
}
#[test]
fn into_option_nonzero_u32_from_invalid_string() {
let input = Value::String(String::from("foo"));
let got = into_option_nonzero_u32(input);
assert!(got.is_err());
}
#[test]
fn into_option_nonzero_u32_from_i64() {
let input = Value::Integer(123);
let got = into_option_nonzero_u32(input);
assert_eq!(got, Ok(NonZeroU32::new(123)));
}
}