Skip to content

Commit

Permalink
Add from_iter and from_iter_with_prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
jayvdb committed Jun 7, 2024
1 parent 62eef7c commit 00d9cb3
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 18 deletions.
82 changes: 78 additions & 4 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ where
/// }
/// temp_env::with_vars(
/// [
/// ("TEST_ENV_HOME", Some("test")),
/// ("TEST_ENV_PATH", Some("test")),
/// ("TEST_ENV_HOME", Some("/test")),
/// ("TEST_ENV_PATH", Some("foo:bar")),
/// ],
/// || {
/// let t: Test = from_env_with_prefix("TEST_ENV").expect("deserialize from env");
///
/// let result = Test {
/// home: "test".to_string(),
/// path: "test".to_string(),
/// home: "/test".to_string(),
/// path: "foo:bar".to_string(),
/// };
/// assert_eq!(t, result);
/// },
Expand All @@ -71,6 +71,80 @@ where
T::deserialize(Deserializer(Node::from_env_with_prefix(prefix)))
}

/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
/// representing keys and values.
///
/// # Examples
///
/// ```
/// use serde::Deserialize;
/// use serde_env::from_iter;
///
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct Test {
/// home: String,
/// path: String,
/// }
/// let vars = [
/// ("HOME", "/test"),
/// ("PATH", "foo:bar"),
/// ];
///
/// let actual: Test = from_iter(vars).expect("deserialize from iter");
///
/// let expected = Test {
/// home: "/test".to_string(),
/// path: "foo:bar".to_string(),
/// };
///
/// assert_eq!(actual, expected);
/// ```
pub fn from_iter<Iter, S, T>(iter: Iter) -> Result<T, Error>
where
Iter: IntoIterator<Item = (S, S)>,
S: AsRef<str>,
T: de::DeserializeOwned,
{
T::deserialize(Deserializer(Node::from_iter(iter)))
}

/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
/// representing keys and values, with a prefix.
///
/// # Examples
///
/// ```
/// use serde::Deserialize;
/// use serde_env::from_iter_with_prefix;
///
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct Test {
/// home: String,
/// path: String,
/// }
/// let vars = ([
/// ("TEST_ENV_HOME", "/test"),
/// ("TEST_ENV_PATH", "foo:bar"),
/// ]);
///
/// let actual: Test = from_iter_with_prefix(vars, "TEST_ENV").expect("deserialize from iter");
///
/// let expected = Test {
/// home: "/test".to_string(),
/// path: "foo:bar".to_string(),
/// };
///
/// assert_eq!(actual, expected);
/// ```
pub fn from_iter_with_prefix<Iter, S, T>(iter: Iter, prefix: &str) -> Result<T, Error>
where
Iter: IntoIterator<Item = (S, S)>,
S: AsRef<str>,
T: de::DeserializeOwned,
{
T::deserialize(Deserializer(Node::from_iter_with_prefix(iter, prefix)))
}

struct Deserializer(Node);

impl<'de> de::Deserializer<'de> for Deserializer {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ mod de;
pub mod error;
mod value;

pub use de::{from_env, from_env_with_prefix};
pub use de::{from_env, from_env_with_prefix, from_iter, from_iter_with_prefix};
pub use error::Error;
51 changes: 38 additions & 13 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,36 +117,61 @@ impl Node {
};
}

/// Construct full tree from env.
pub fn from_env() -> Self {
/// Construct full tree from an iterator.
pub(crate) fn from_iter<Iter, S>(iter: Iter) -> Self
where
S: AsRef<str>,
Iter: IntoIterator<Item = (S, S)>,
{
let mut root = Node::new(String::default());

let vars = env::vars()
.map(|(k, v)| (k.to_lowercase(), v))
.filter(|(_, v)| !v.is_empty());
let vars = iter
.into_iter()
.map(|(k, v)| (k.as_ref().to_lowercase(), v))
.filter(|(_, v)| !v.as_ref().is_empty());

for (k, v) in vars {
root.push(&k, &v)
root.push(&k, v.as_ref())
}

root
}
/// Construct full tree from env with prefix.
pub fn from_env_with_prefix(prefix: &str) -> Self {

/// Construct full tree from an iterator with prefix.
pub(crate) fn from_iter_with_prefix<Iter, S>(iter: Iter, prefix: &str) -> Self
where
S: AsRef<str>,
Iter: IntoIterator<Item = (S, S)>,
{
let prefix = format!("{}_", prefix);
let mut root = Node::new(&prefix);
let vars = env::vars().filter_map(|(k, v)| {
if v.is_empty() {
let mut root = Node::new(String::default());

let vars = iter.into_iter().filter_map(|(k, v)| {
if v.as_ref().is_empty() {
None
} else {
k.strip_prefix(&prefix).map(|k| (k.to_lowercase(), v))
k.as_ref()
.strip_prefix(&prefix)
.map(|k| (k.to_lowercase(), v))
}
});

for (k, v) in vars {
root.push(&k, &v)
root.push(&k, v.as_ref())
}

root
}

/// Construct full tree from env.
pub(crate) fn from_env() -> Self {
Node::from_iter(env::vars())
}

/// Construct full tree from env with prefix.
pub(crate) fn from_env_with_prefix(prefix: &str) -> Self {
Node::from_iter_with_prefix(env::vars(), prefix)
}
}

#[cfg(test)]
Expand Down

0 comments on commit 00d9cb3

Please sign in to comment.