use crate::util::config::value;
use crate::util::config::{Config, ConfigError, ConfigKey};
use crate::util::config::{ConfigValue as CV, Definition, Value};
use serde::{de, de::IntoDeserializer};
use std::collections::HashSet;
use std::vec;
#[derive(Clone)]
pub(super) struct Deserializer<'config> {
pub(super) config: &'config Config,
pub(super) key: ConfigKey,
pub(super) env_prefix_ok: bool,
}
macro_rules! deserialize_method {
($method:ident, $visit:ident, $getter:ident) => {
fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let v = self
.config
.$getter(&self.key)?
.ok_or_else(|| ConfigError::missing(&self.key))?;
let Value { val, definition } = v;
let res: Result<V::Value, ConfigError> = visitor.$visit(val);
res.map_err(|e| e.with_key_context(&self.key, definition))
}
};
}
impl<'de, 'config> de::Deserializer<'de> for Deserializer<'config> {
type Error = ConfigError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let cv = self.config.get_cv_with_env(&self.key)?;
if let Some(cv) = cv {
let res: (Result<V::Value, ConfigError>, Definition) = match cv {
CV::Integer(i, def) => (visitor.visit_i64(i), def),
CV::String(s, def) => (visitor.visit_string(s), def),
CV::List(_, def) => (visitor.visit_seq(ConfigSeqAccess::new(self.clone())?), def),
CV::Table(_, def) => (
visitor.visit_map(ConfigMapAccess::new_map(self.clone())?),
def,
),
CV::Boolean(b, def) => (visitor.visit_bool(b), def),
};
let (res, def) = res;
return res.map_err(|e| e.with_key_context(&self.key, def));
}
Err(ConfigError::missing(&self.key))
}
deserialize_method!(deserialize_bool, visit_bool, get_bool);
deserialize_method!(deserialize_i8, visit_i64, get_integer);
deserialize_method!(deserialize_i16, visit_i64, get_integer);
deserialize_method!(deserialize_i32, visit_i64, get_integer);
deserialize_method!(deserialize_i64, visit_i64, get_integer);
deserialize_method!(deserialize_u8, visit_i64, get_integer);
deserialize_method!(deserialize_u16, visit_i64, get_integer);
deserialize_method!(deserialize_u32, visit_i64, get_integer);
deserialize_method!(deserialize_u64, visit_i64, get_integer);
deserialize_method!(deserialize_string, visit_string, get_string_priv);
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if self.config.has_key(&self.key, self.env_prefix_ok)? {
visitor.visit_some(self)
} else {
visitor.visit_none()
}
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if name == value::NAME && fields == value::FIELDS {
return visitor.visit_map(ValueDeserializer::new(self)?);
}
visitor.visit_map(ConfigMapAccess::new_struct(self, fields)?)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_map(ConfigMapAccess::new_map(self)?)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_seq(ConfigSeqAccess::new(self)?)
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_seq(ConfigSeqAccess::new(self)?)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_seq(ConfigSeqAccess::new(self)?)
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let merge = if name == "StringList" {
true
} else if name == "UnmergedStringList" {
false
} else {
return visitor.visit_newtype_struct(self);
};
let vals = self.config.get_list_or_string(&self.key, merge)?;
let vals: Vec<String> = vals.into_iter().map(|vd| vd.0).collect();
visitor.visit_newtype_struct(vals.into_deserializer())
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let value = self
.config
.get_string_priv(&self.key)?
.ok_or_else(|| ConfigError::missing(&self.key))?;
let Value { val, definition } = value;
visitor
.visit_enum(val.into_deserializer())
.map_err(|e: ConfigError| e.with_key_context(&self.key, definition))
}
serde::forward_to_deserialize_any! {
f32 f64 char str bytes
byte_buf unit unit_struct
identifier ignored_any
}
}
struct ConfigMapAccess<'config> {
de: Deserializer<'config>,
fields: Vec<KeyKind>,
field_index: usize,
}
#[derive(Debug, PartialEq, Eq, Hash)]
enum KeyKind {
Normal(String),
CaseSensitive(String),
}
impl<'config> ConfigMapAccess<'config> {
fn new_map(de: Deserializer<'config>) -> Result<ConfigMapAccess<'config>, ConfigError> {
let mut fields = Vec::new();
if let Some(mut v) = de.config.get_table(&de.key)? {
for (key, _value) in v.val.drain() {
fields.push(KeyKind::CaseSensitive(key));
}
}
if de.config.cli_unstable().advanced_env {
let env_prefix = format!("{}_", de.key.as_env_key());
for env_key in de.config.env_keys() {
if let Some(rest) = env_key.strip_prefix(&env_prefix) {
let part = rest.splitn(2, '_').next().unwrap();
fields.push(KeyKind::CaseSensitive(part.to_string()));
}
}
}
Ok(ConfigMapAccess {
de,
fields,
field_index: 0,
})
}
fn new_struct(
de: Deserializer<'config>,
given_fields: &'static [&'static str],
) -> Result<ConfigMapAccess<'config>, ConfigError> {
let table = de.config.get_table(&de.key)?;
if let Some(v) = table.as_ref() {
let unused_keys = v
.val
.iter()
.filter(|(k, _v)| !given_fields.iter().any(|gk| gk == k));
for (unused_key, unused_value) in unused_keys {
de.config.shell().warn(format!(
"unused config key `{}.{}` in `{}`",
de.key,
unused_key,
unused_value.definition()
))?;
}
}
let mut fields = HashSet::new();
for field in given_fields {
let mut field_key = de.key.clone();
field_key.push(field);
for env_key in de.config.env_keys() {
if env_key.starts_with(field_key.as_env_key()) {
fields.insert(KeyKind::Normal(field.to_string()));
}
}
}
if let Some(v) = table {
for key in v.val.keys() {
fields.insert(KeyKind::Normal(key.clone()));
}
}
Ok(ConfigMapAccess {
de,
fields: fields.into_iter().collect(),
field_index: 0,
})
}
}
impl<'de, 'config> de::MapAccess<'de> for ConfigMapAccess<'config> {
type Error = ConfigError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: de::DeserializeSeed<'de>,
{
if self.field_index >= self.fields.len() {
return Ok(None);
}
let field = match &self.fields[self.field_index] {
KeyKind::Normal(s) | KeyKind::CaseSensitive(s) => s.as_str(),
};
seed.deserialize(field.into_deserializer()).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: de::DeserializeSeed<'de>,
{
let field = &self.fields[self.field_index];
self.field_index += 1;
let field = match field {
KeyKind::Normal(field) => {
self.de.key.push(field);
field
}
KeyKind::CaseSensitive(field) => {
self.de.key.push_sensitive(field);
field
}
};
let env_prefix = format!("{}_", field).replace('-', "_");
let env_prefix_ok = !self.fields.iter().any(|field| {
let field = match field {
KeyKind::Normal(s) | KeyKind::CaseSensitive(s) => s.as_str(),
};
field.replace('-', "_").starts_with(&env_prefix)
});
let result = seed.deserialize(Deserializer {
config: self.de.config,
key: self.de.key.clone(),
env_prefix_ok,
});
self.de.key.pop();
result
}
}
struct ConfigSeqAccess {
list_iter: vec::IntoIter<(String, Definition)>,
}
impl ConfigSeqAccess {
fn new(de: Deserializer<'_>) -> Result<ConfigSeqAccess, ConfigError> {
let mut res = Vec::new();
if let Some(v) = de.config._get_list(&de.key)? {
res.extend(v.val);
}
de.config.get_env_list(&de.key, &mut res)?;
Ok(ConfigSeqAccess {
list_iter: res.into_iter(),
})
}
}
impl<'de> de::SeqAccess<'de> for ConfigSeqAccess {
type Error = ConfigError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: de::DeserializeSeed<'de>,
{
match self.list_iter.next() {
Some((value, def)) => {
let maybe_value_de = ValueDeserializer::new_with_string(value, def);
seed.deserialize(maybe_value_de).map(Some)
}
None => Ok(None),
}
}
}
struct ValueDeserializer<'config> {
hits: u32,
definition: Definition,
de: Option<Deserializer<'config>>,
str_value: Option<String>,
}
impl<'config> ValueDeserializer<'config> {
fn new(de: Deserializer<'config>) -> Result<ValueDeserializer<'config>, ConfigError> {
let definition = {
let env = de.key.as_env_key();
let env_def = Definition::Environment(env.to_string());
match (de.config.env.contains_key(env), de.config.get_cv(&de.key)?) {
(true, Some(cv)) => {
if env_def.is_higher_priority(cv.definition()) {
env_def
} else {
cv.definition().clone()
}
}
(false, Some(cv)) => cv.definition().clone(),
(_, None) => env_def,
}
};
Ok(ValueDeserializer {
hits: 0,
definition,
de: Some(de),
str_value: None,
})
}
fn new_with_string(s: String, definition: Definition) -> ValueDeserializer<'config> {
ValueDeserializer {
hits: 0,
definition,
de: None,
str_value: Some(s),
}
}
}
impl<'de, 'config> de::MapAccess<'de> for ValueDeserializer<'config> {
type Error = ConfigError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: de::DeserializeSeed<'de>,
{
self.hits += 1;
match self.hits {
1 => seed
.deserialize(value::VALUE_FIELD.into_deserializer())
.map(Some),
2 => seed
.deserialize(value::DEFINITION_FIELD.into_deserializer())
.map(Some),
_ => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: de::DeserializeSeed<'de>,
{
if self.hits == 1 {
if let Some(de) = &self.de {
return seed
.deserialize(de.clone())
.map_err(|e| e.with_key_context(&de.key, self.definition.clone()));
} else {
return seed
.deserialize(self.str_value.as_ref().unwrap().clone().into_deserializer());
}
}
match &self.definition {
Definition::Path(path) => {
seed.deserialize(Tuple2Deserializer(0i32, path.to_string_lossy()))
}
Definition::Environment(env) => {
seed.deserialize(Tuple2Deserializer(1i32, env.as_str()))
}
Definition::Cli(path) => {
let str = path
.as_ref()
.map(|p| p.to_string_lossy())
.unwrap_or_default();
seed.deserialize(Tuple2Deserializer(2i32, str))
}
}
}
}
impl<'de, 'config> de::Deserializer<'de> for ValueDeserializer<'config> {
type Error = ConfigError;
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_str(&self.str_value.expect("string expected"))
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_string(self.str_value.expect("string expected"))
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if name == value::NAME && fields == value::FIELDS {
return visitor.visit_map(self);
}
unimplemented!("only strings and Value can be deserialized from a sequence");
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_string(self.str_value.expect("string expected"))
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_unit()
}
serde::forward_to_deserialize_any! {
i8 i16 i32 i64
u8 u16 u32 u64
option
newtype_struct seq tuple tuple_struct map enum bool
f32 f64 char bytes
byte_buf unit unit_struct
identifier
}
}
struct Tuple2Deserializer<T, U>(T, U);
impl<'de, T, U> de::Deserializer<'de> for Tuple2Deserializer<T, U>
where
T: IntoDeserializer<'de, ConfigError>,
U: IntoDeserializer<'de, ConfigError>,
{
type Error = ConfigError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, ConfigError>
where
V: de::Visitor<'de>,
{
struct SeqVisitor<T, U> {
first: Option<T>,
second: Option<U>,
}
impl<'de, T, U> de::SeqAccess<'de> for SeqVisitor<T, U>
where
T: IntoDeserializer<'de, ConfigError>,
U: IntoDeserializer<'de, ConfigError>,
{
type Error = ConfigError;
fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: de::DeserializeSeed<'de>,
{
if let Some(first) = self.first.take() {
return seed.deserialize(first.into_deserializer()).map(Some);
}
if let Some(second) = self.second.take() {
return seed.deserialize(second.into_deserializer()).map(Some);
}
Ok(None)
}
}
visitor.visit_seq(SeqVisitor {
first: Some(self.0),
second: Some(self.1),
})
}
serde::forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
bytes byte_buf map struct option unit newtype_struct
ignored_any unit_struct tuple_struct tuple enum identifier
}
}