use lazy_static::lazy_static;
use regex::Regex;
use serde::de::{
self, Deserialize, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor,
};
use std::collections::BTreeMap;
use std::fmt;
use std::marker::PhantomData;
use super::interpolation::{raw, InterpolatableValue, RawOr};
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn is_false(b: &bool) -> bool {
!b
}
struct ToStringVisitor;
impl<'de> Visitor<'de> for ToStringVisitor {
type Value = String;
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(format!("{}", v))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(format!("{}", v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(format!("{}", v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(v.to_owned())
}
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a value which can be converted to a string")
}
}
struct ConvertToString(String);
impl<'de> Deserialize<'de> for ConvertToString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer
.deserialize_string(ToStringVisitor)
.map(ConvertToString)
}
}
pub fn deserialize_map_or_key_value_list<'de, D>(
deserializer: D,
) -> Result<BTreeMap<String, RawOr<String>>, D::Error>
where
D: Deserializer<'de>,
{
struct MapOrKeyValueListVisitor;
impl<'de> Visitor<'de> for MapOrKeyValueListVisitor {
type Value = BTreeMap<String, RawOr<String>>;
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut map: BTreeMap<String, RawOr<String>> = BTreeMap::new();
while let Some(key) = visitor.next_key::<String>()? {
if map.contains_key(&key) {
let msg = format!("duplicate map key: {}", &key);
return Err(<V::Error as de::Error>::custom(msg));
}
let ConvertToString(val) = visitor.next_value::<ConvertToString>()?;
let raw_or_value = raw(val)
.map_err(|e| <V::Error as de::Error>::custom(format!("{}", e)))?;
map.insert(key, raw_or_value);
}
Ok(map)
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
lazy_static! {
static ref KEY_VALUE: Regex =
Regex::new("^([^=]+)=(.*)$").unwrap();
}
let mut map: BTreeMap<String, RawOr<String>> = BTreeMap::new();
while let Some(key_value) = visitor.next_element::<String>()? {
let caps = KEY_VALUE.captures(&key_value).ok_or_else(|| {
let msg = format!("expected KEY=value, got: <{}>", &key_value);
<V::Error as de::Error>::custom(msg)
})?;
let key = caps.get(1).unwrap().as_str();
let value = caps.get(2).unwrap().as_str();
if map.contains_key(key) {
let msg = format!("duplicate map key: {}", key);
return Err(<V::Error as de::Error>::custom(msg));
}
let raw_or_value = raw(value.to_owned())
.map_err(|e| <V::Error as de::Error>::custom(format!("{}", e)))?;
map.insert(key.to_owned(), raw_or_value);
}
Ok(map)
}
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a map or a key/value list")
}
}
deserializer.deserialize_any(MapOrKeyValueListVisitor)
}
pub fn deserialize_map_or_default_list<'de, T, D>(
deserializer: D,
) -> Result<BTreeMap<String, T>, D::Error>
where
T: Default + DeserializeOwned,
D: Deserializer<'de>,
{
struct MapOrDefaultListVisitor<T>(PhantomData<T>)
where
T: Default + DeserializeOwned;
impl<'de, T: Default + DeserializeOwned> Visitor<'de> for MapOrDefaultListVisitor<T> {
type Value = BTreeMap<String, T>;
fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(visitor);
Deserialize::deserialize(mvd)
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut map: Self::Value = BTreeMap::new();
while let Some(key) = visitor.next_element::<String>()? {
map.insert(key, Default::default());
}
Ok(map)
}
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a map or a list of strings")
}
}
deserializer.deserialize_any(MapOrDefaultListVisitor(PhantomData::<T>))
}
pub fn deserialize_item_or_list<'de, T, D>(
deserializer: D,
) -> Result<Vec<RawOr<T>>, D::Error>
where
T: InterpolatableValue,
D: Deserializer<'de>,
{
struct StringOrListVisitor<T>(PhantomData<T>)
where
T: InterpolatableValue;
impl<'de, T> Visitor<'de> for StringOrListVisitor<T>
where
T: InterpolatableValue,
{
type Value = Vec<RawOr<T>>;
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let v = raw(value).map_err(|err| E::custom(format!("{}", err)))?;
Ok(vec![v])
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut items: Vec<RawOr<T>> = vec![];
while let Some(item) = visitor.next_element::<String>()? {
let v = raw(item).map_err(|err| {
<V::Error as de::Error>::custom(format!("{}", err))
})?;
items.push(v);
}
Ok(items)
}
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a string or a list of strings")
}
}
deserializer.deserialize_seq(StringOrListVisitor(PhantomData))
}
pub fn deserialize_map_struct_or_null<'de, T, D>(
deserializer: D,
) -> Result<BTreeMap<String, T>, D::Error>
where
T: Deserialize<'de> + Default,
D: Deserializer<'de>,
{
let with_nulls: BTreeMap<String, Option<T>> =
Deserialize::deserialize(deserializer)?;
let mut result = BTreeMap::new();
for (k, v) in with_nulls {
result.insert(k, v.unwrap_or_default());
}
Ok(result)
}