#![allow(clippy::needless_doctest_main)]
use serde::{de::value::MapDeserializer, Deserialize};
use crate::{Error, Result};
use self::{key::Key, value::Value};
mod key;
mod util;
mod value;
pub fn from_env<'de, T>() -> Result<T>
where
T: Deserialize<'de>,
{
from_iter(std::env::vars_os())
}
pub fn from_env_prefixed<'de, T>(prefix: &str) -> Result<T>
where
T: Deserialize<'de>,
{
from_iter(
std::env::vars_os().filter_map(|(name, value)| match name.to_str() {
Some(name) => Some((std::ffi::OsString::from(name.strip_prefix(prefix)?), value)),
_ => None,
}),
)
}
pub fn from_iter<'de, T>(
iter: impl Iterator<Item = (impl Into<Key<'de>>, impl Into<Value<'de>>)>,
) -> Result<T>
where
T: Deserialize<'de>,
{
let mut deserializer =
EnvDeserializer::from_iter(iter.map(|(key, value)| (key.into(), value.into())));
T::deserialize(&mut deserializer)
}
struct EnvDeserializer<'de, I: Iterator<Item = (Key<'de>, Value<'de>)>>(
MapDeserializer<'de, I, Error>,
);
impl<'de, I> EnvDeserializer<'de, I>
where
I: Iterator<Item = (Key<'de>, Value<'de>)>,
{
pub fn from_iter(iter: I) -> Self {
Self(MapDeserializer::new(iter))
}
}
impl<'de, 'a, I> serde::de::Deserializer<'de> for &'a mut EnvDeserializer<'de, I>
where
I: Iterator<Item = (Key<'de>, Value<'de>)>,
{
type Error = Error;
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_map(&mut self.0)
}
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
util::unsupported_types! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct tuple
any tuple_struct identifier enum map seq ignored_any
}
}