Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 84 additions & 49 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
use std::path::Path;

use serde::de;

use crate::{Error, error::Result};
use super::error::{Error, Result};

pub fn from_iter<T, Iter>(iter: Iter) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
Iter: IntoIterator<Item = (String, String)>,
{
from_iter_inner::<T, Iter>(None, iter)
}

pub fn from_iter_inner<T, Iter>(prefix: Option<&str>, iter: Iter) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
Iter: IntoIterator<Item = (String, String)>,
{
match prefix {
Some(pref) => {
envy::prefixed(pref.to_uppercase()).from_iter::<_, T>(iter)
}
Some(pref) => envy::prefixed(pref.to_uppercase()).from_iter::<_, T>(iter),
None => {
// No prefix provided, use default behavior
envy::from_iter::<_, T>(iter)
}
}.map_err(Error::new)
}
.map_err(Error::new)
}

/// Deserialize program-available environment variables into an instance of type `T`.
Expand All @@ -45,32 +42,26 @@ where
/// user: String,
/// }
///
/// fn from_env_example() -> Result<(), Error> {
/// let t: Test = from_env()?;
/// println!("{:?}", t);
///
/// Ok(())
/// }
/// let value = from_env::<Test>().expect("Failed to deserialize from environment");
///
/// println!("{:?}", value);
/// ```
pub fn from_env<T>() -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
from_env_inner(None)
}

pub fn from_env_inner<T>(prefix: Option<&str>) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
match prefix {
Some(pref) => {
envy::prefixed(pref.to_uppercase()).from_env::<T>()
}
None => {
envy::from_env::<T>()
}
}.map_err(Error::new)
Some(pref) => envy::prefixed(pref.to_uppercase()).from_env::<T>(),
None => envy::from_env::<T>(),
}
.map_err(Error::new)
}

/// Deserialize environment variables from a string into an instance of type `T`.
Expand All @@ -80,24 +71,21 @@ where
/// ```
/// use serde_envfile::{from_str, Value, Error};
///
/// fn from_str_example() -> Result<(), Error> {
/// let e = "HELLO=world";
/// let v: Value = from_str(e)?;
/// println!("{:?}", v);
///
/// Ok(())
/// }
/// let env = "HELLO=world";
/// let value = from_str::<Value>(env).expect("Failed to deserialize from string");
///
/// println!("{:?}", value);
/// ```
pub fn from_str<T>(input: &str) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
from_str_inner::<T>(None, input)
}

pub fn from_str_inner<'a, T>(prefix: Option<&'a str>, input: &'a str) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
let mut env = Vec::new();

Expand All @@ -109,37 +97,69 @@ where
from_iter_inner::<T, _>(prefix, env)
}

/// Deserialize an environment variable file into an instance of type `T`.
/// Deserialize environment variables from a reader into an instance of type `T`.
///
/// # Example
///
/// ```
/// use std::path::PathBuf;
/// use serde_envfile::{from_file, Value, Error};
/// use std::io::Cursor;
/// use serde_envfile::{from_reader, Value, Error};
///
/// fn from_file_example() -> Result<(), Error> {
/// let v: Value = from_file(&PathBuf::from(".env"))?;
/// println!("{:?}", v);
/// let input = Cursor::new("HELLO=world");
/// let value = from_reader::<_, Value>(input).expect("Envfile deserialization failed");
///
/// Ok(())
/// }
/// println!("{:?}", value);
/// ```
pub fn from_reader<R, T>(reader: R) -> Result<T>
where
R: std::io::Read,
T: serde::de::DeserializeOwned,
{
from_reader_inner(None, reader)
}

pub(crate) fn from_reader_inner<R, T>(prefix: Option<&str>, reader: R) -> Result<T>
where
R: std::io::Read,
T: serde::de::DeserializeOwned,
{
let mut env = Vec::new();

for pair in dotenvy::from_read_iter(reader) {
let (key, value) = pair.map_err(Error::new)?;
env.push((key, value));
}

from_iter_inner::<T, _>(prefix, env)
}

/// Deserialize an environment variable file into an instance of type `T`.
///
/// # Example
///
/// ```no_run
/// use std::path::PathBuf;
/// use serde_envfile::{Value, from_file};
///
/// let path = PathBuf::from(".env");
/// let value = from_file::<Value>(&path).expect("Failed to deserialize from file");
///
/// println!("{:?}", value);
/// ```
pub fn from_file<T>(path: &Path) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
from_file_inner(None, path)
}

pub fn from_file_inner<T>(prefix: Option<&str>, path: &Path) -> Result<T>
where
T: de::DeserializeOwned,
T: serde::de::DeserializeOwned,
{
let mut env = Vec::new();

for pair in dotenvy::from_filename_iter(path)
.map_err(Error::new)?
{
for pair in dotenvy::from_filename_iter(path).map_err(Error::new)? {
let (key, value) = pair.map_err(Error::new)?;
env.push((key, value));
}
Expand All @@ -152,12 +172,12 @@ mod tests {
use std::{
env::{set_var, vars},
fs::write,
io::{SeekFrom, prelude::*},
io::{Cursor, Seek, SeekFrom},
};

use tempfile::NamedTempFile;

use super::*;
use super::{from_env, from_file, from_reader, from_str};
use crate::Value;

#[test]
Expand All @@ -184,14 +204,29 @@ mod tests {
assert_eq!("world", env.get("hello").unwrap());
}

#[test]
fn deserialize_from_reader() {
//* Given
let input = "HELLO=world";

let reader = Cursor::new(input);

//* When
let env: Value = from_reader(reader).expect("Failed to deserialize from reader");

//* Then
assert_eq!(env.len(), 1);
assert_eq!("world", env.get("hello").unwrap());
}

#[test]
fn from_file_test() {
let input = "HELLO=world";
let mut file = NamedTempFile::new().unwrap();
write(file.path(), input).unwrap();
file.seek(SeekFrom::Start(0)).unwrap();

let env: Value = from_file(file.path()).unwrap();
let env: Value = from_file(file.path()).expect("Failed to deserialize from file");

assert_eq!(env.len(), 1);
assert_eq!("world", env.get("hello").unwrap());
Expand Down
15 changes: 3 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,12 @@ pub(crate) mod prefixed;
pub(crate) mod ser;
pub(crate) mod value;

pub use de::{from_env, from_file, from_reader, from_str};
pub use error::Error;

pub use de::from_env;
pub use de::from_file;
pub use de::from_str;

pub use ser::Serializer;
pub use ser::to_file;
pub use ser::to_string;

pub use prefixed::{Prefixed, prefixed};
pub use ser::{Serializer, to_file, to_string, to_writer};
pub use value::Value;

pub use prefixed::Prefixed;
pub use prefixed::prefixed;

#[cfg(test)]
mod tests {
use crate::{Value, from_str, to_string};
Expand Down
Loading