From 00d9cb38aac0e07335e23c8ec12e0b87955a70d5 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sat, 8 Jun 2024 06:10:32 +0800 Subject: [PATCH] Add from_iter and from_iter_with_prefix --- src/de.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 2 +- src/value.rs | 51 +++++++++++++++++++++++--------- 3 files changed, 117 insertions(+), 18 deletions(-) diff --git a/src/de.rs b/src/de.rs index bb83b60..76b072e 100644 --- a/src/de.rs +++ b/src/de.rs @@ -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); /// }, @@ -71,6 +71,80 @@ where T::deserialize(Deserializer(Node::from_env_with_prefix(prefix))) } +/// Deserialize into struct via an iterable of `(AsRef, AsRef)` +/// 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: Iter) -> Result +where + Iter: IntoIterator, + S: AsRef, + T: de::DeserializeOwned, +{ + T::deserialize(Deserializer(Node::from_iter(iter))) +} + +/// Deserialize into struct via an iterable of `(AsRef, AsRef)` +/// 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: Iter, prefix: &str) -> Result +where + Iter: IntoIterator, + S: AsRef, + T: de::DeserializeOwned, +{ + T::deserialize(Deserializer(Node::from_iter_with_prefix(iter, prefix))) +} + struct Deserializer(Node); impl<'de> de::Deserializer<'de> for Deserializer { diff --git a/src/lib.rs b/src/lib.rs index bad7c76..bf58b15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/value.rs b/src/value.rs index 4dbc8bc..64e0e51 100644 --- a/src/value.rs +++ b/src/value.rs @@ -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: Iter) -> Self + where + S: AsRef, + Iter: IntoIterator, + { 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: Iter, prefix: &str) -> Self + where + S: AsRef, + Iter: IntoIterator, + { 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)]