commit
3686486847
30 changed files with 457 additions and 2382 deletions
3
.vim/coc-settings.json
Normal file
3
.vim/coc-settings.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rust-analyzer.cargo.features": "all"
|
||||||
|
}
|
1371
Cargo.lock
generated
1371
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
48
Cargo.toml
48
Cargo.toml
|
@ -1,7 +1,49 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"itconfig",
|
"estring",
|
||||||
"itconfig-macro",
|
"enve_mod",
|
||||||
"itconfig-tests",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "enve"
|
||||||
|
version = "1.1.1"
|
||||||
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
|
description = "Easy build a configs from environment variables and use it in globally."
|
||||||
|
categories = ["config", "web-programming"]
|
||||||
|
keywords = ["config", "env", "configuration", "environment", "macro"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/pleshevskiy/enve"
|
||||||
|
homepage = "https://github.com/pleshevskiy/enve"
|
||||||
|
documentation = "https://docs.rs/enve"
|
||||||
|
readme = "../README.md"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
number = ["estring/number"]
|
||||||
|
bool = ["estring/bool"]
|
||||||
|
vec = ["estring/vec"]
|
||||||
|
|
||||||
|
macro = ["enve_mod"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
estring = "0.1"
|
||||||
|
enve_mod = { version = "1.1", path = "./enve_mod", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
criterion = "0.3.1"
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
|
# https://docs.rs/about
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "calc"
|
||||||
|
required-features = ["number", "vec"]
|
||||||
|
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2019 IceTemple
|
Copyright (c) 2019-2022 pleshevskiy
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
56
README.md
56
README.md
|
@ -1,10 +1,10 @@
|
||||||
# itconfig
|
# enve
|
||||||
|
|
||||||
[![CI](https://github.com/icetemple/itconfig-rs/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/icetemple/itconfig-rs/actions/workflows/ci.yml)
|
[![CI](https://github.com/pleshevskiy/enve/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/pleshevskiy/enve/actions/workflows/ci.yml)
|
||||||
[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
|
[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
|
||||||
[![Documentation](https://docs.rs/itconfig/badge.svg)](https://docs.rs/itconfig)
|
[![Documentation](https://docs.rs/pleshevskiy/badge.svg)](https://docs.rs/enve)
|
||||||
[![Crates.io](https://img.shields.io/crates/v/itconfig)](https://crates.io/crates/itconfig)
|
[![Crates.io](https://img.shields.io/crates/v/enve)](https://crates.io/crates/enve)
|
||||||
![Crates.io](https://img.shields.io/crates/l/itconfig)
|
![Crates.io](https://img.shields.io/crates/l/enve)
|
||||||
|
|
||||||
Easy build a configs from environment variables and use it in globally.
|
Easy build a configs from environment variables and use it in globally.
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ of it I decided to create my own library.
|
||||||
|
|
||||||
The MSRV is 1.39.0
|
The MSRV is 1.39.0
|
||||||
|
|
||||||
Add `itconfig = { version = "1.0", features = ["macro"] }` as a dependency in
|
Add `enve = { version = "1.0", features = ["mod"] }` as a dependency in
|
||||||
`Cargo.toml`.
|
`Cargo.toml`.
|
||||||
|
|
||||||
`Cargo.toml` example:
|
`Cargo.toml` example:
|
||||||
|
@ -35,17 +35,16 @@ version = "0.1.0"
|
||||||
authors = ["Me <user@rust-lang.org>"]
|
authors = ["Me <user@rust-lang.org>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itconfig = { version = "1.0", features = ["macro"] }
|
enve = { version = "1.0", features = ["mod"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use itconfig::config;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
//use dotenv::dotenv;
|
//use dotenv::dotenv;
|
||||||
|
|
||||||
config! {
|
enve::mod! {
|
||||||
DEBUG: bool => false,
|
DEBUG: bool => false,
|
||||||
|
|
||||||
#[env_name = "APP_HOST"]
|
#[env_name = "APP_HOST"]
|
||||||
|
@ -97,7 +96,6 @@ Macro is an optional feature, disabled by default. You can use this library
|
||||||
without macro
|
without macro
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use itconfig::*;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
// use dotenv::dotenv;
|
// use dotenv::dotenv;
|
||||||
|
|
||||||
|
@ -106,9 +104,9 @@ fn main() {
|
||||||
// or
|
// or
|
||||||
env::set_var("DATABASE_URL", "postgres://127.0.0.1:5432/test");
|
env::set_var("DATABASE_URL", "postgres://127.0.0.1:5432/test");
|
||||||
|
|
||||||
let database_url = get_env::<String>("DATABASE_URL").unwrap();
|
let database_url = enve::get::<String>("DATABASE_URL").unwrap();
|
||||||
let new_profile: bool = get_env_or_default("FEATURE_NEW_PROFILE", false);
|
let new_profile: bool = enve::get("FEATURE_NEW_PROFILE").unwrap_or_default();
|
||||||
let articles_per_page: u32 = get_env_or_set_default("ARTICLES_PER_PAGE", 10);
|
let articles_per_page: u32 = enve::get_or_set_default("ARTICLES_PER_PAGE", 10);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -120,39 +118,19 @@ cargo test --all-features
|
||||||
|
|
||||||
## Available features
|
## Available features
|
||||||
|
|
||||||
- **default** - ["primitives"]
|
|
||||||
- **macro** - Activates `config!` macros for easy configure web application.
|
- **macro** - Activates `config!` macros for easy configure web application.
|
||||||
- **primitives** - Group for features: `numbers` and `bool`.
|
- **number** - Group for features: `int`, `uint` and `float`.
|
||||||
- **numbers** - Group for features: `int`, `uint` and `float`.
|
- **bool** - impl EnvString for `bool` type `serde_json` package). ⚠
|
||||||
- **int** - Group for features: `i8`, `i16`, `i32`, `i64`, `i128` and `isize`.
|
**_DEPRECATED_**
|
||||||
- **uint** - Group for features: `u8`, `u16`, `u32`, `u64`, `u128` and `usize`.
|
|
||||||
- **float** - Group for features: `f32` and `f64`
|
|
||||||
- **i8** - impl EnvString for `i8` type
|
|
||||||
- **i16** - impl EnvString for `i16` type
|
|
||||||
- **i32** - impl EnvString for `i32` type
|
|
||||||
- **i64** - impl EnvString for `i64` type
|
|
||||||
- **i128** - impl EnvString for `i128` type
|
|
||||||
- **isize** - impl EnvString for `isize` type
|
|
||||||
- **u8** - impl EnvString for `u8` type
|
|
||||||
- **u16** - impl EnvString for `u16` type
|
|
||||||
- **u32** - impl EnvString for `u32` type
|
|
||||||
- **u64** - impl EnvString for `u64` type
|
|
||||||
- **u128** - impl EnvString for `u128` type
|
|
||||||
- **usize** - impl EnvString for `usize` type
|
|
||||||
- **f32** - impl EnvString for `f32` type
|
|
||||||
- **f64** - impl EnvString for `f64` type
|
|
||||||
- **bool** - impl EnvString for `bool` type
|
|
||||||
- **json_array** - Add EnvString impl for vector type (uses optional
|
|
||||||
`serde_json` package). ⚠ **_DEPRECATED_**
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT] © [Ice Temple](https://github.com/icetemple)
|
[MIT] © [pleshevskiy](https://github.com/pleshevskiy)
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
[pleshevskiy](https://github.com/pleshevskiy) (Dmitriy Pleshevskiy) – creator,
|
[pleshevskiy](https://github.com/pleshevskiy) (Dmitriy Pleshevskiy) – creator,
|
||||||
maintainer.
|
maintainer.
|
||||||
|
|
||||||
[documentation]: https://docs.rs/itconfig
|
[documentation]: https://docs.rs/enve
|
||||||
[MIT]: https://github.com/icetemple/itconfig-rs/blob/master/LICENSE
|
[MIT]: https://github.com/icetemple/enve-rs/blob/master/LICENSE
|
||||||
|
|
|
@ -4,14 +4,14 @@ use std::env;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate itconfig;
|
extern crate enve;
|
||||||
|
|
||||||
fn setup_env_var(key: &'static str, initial: String) {
|
fn setup_env_var(key: &'static str, initial: String) {
|
||||||
env::set_var(key, initial);
|
env::set_var(key, initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_get_env() -> u32 {
|
fn source_get_env() -> u32 {
|
||||||
itconfig::get_env::<u32>("TEST").unwrap()
|
enve::get::<u32>("TEST").unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lazy_get_env() -> u32 {
|
fn lazy_get_env() -> u32 {
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "itconfig-macro"
|
name = "enve_mod"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
description = "Easy build a configs from environment variables and use it in globally."
|
description = "Easy build a configs from environment variables and use it in globally."
|
||||||
|
@ -7,9 +7,9 @@ categories = ["config", "web-programming"]
|
||||||
keywords = ["config", "env", "configuration", "environment", "macro"]
|
keywords = ["config", "env", "configuration", "environment", "macro"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/icetemple/itconfig-rs"
|
repository = "https://github.com/pleshevskiy/enve"
|
||||||
homepage = "https://github.com/icetemple/itconfig-rs"
|
homepage = "https://github.com/pleshevskiy/enve"
|
||||||
documentation = "https://docs.rs/itconfig"
|
documentation = "https://docs.rs/enve"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -22,9 +22,8 @@ quote = "1.0.9"
|
||||||
proc-macro2 = "1.0.24"
|
proc-macro2 = "1.0.24"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
itconfig = { path = "../itconfig" }
|
enve = { path = ".." }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "icetemple/itconfig-rs" }
|
maintenance = { status = "actively-developed" }
|
||||||
maintenance = { status = "passively-maintained" }
|
|
15
examples/README.md
Normal file
15
examples/README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
## Calculator
|
||||||
|
|
||||||
|
Fun calculator based on environment variables
|
||||||
|
|
||||||
|
```
|
||||||
|
E=2*2-1-1+5*3-10 cargo run --example calc --all-features
|
||||||
|
```
|
||||||
|
|
||||||
|
Limits:
|
||||||
|
|
||||||
|
- Supports `*`, `+`, `-`
|
||||||
|
- You cannot start from a negative number. `E=-10`. Solution: start from `0`.
|
||||||
|
`E=0-10`.
|
36
examples/calc.rs
Normal file
36
examples/calc.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use enve::estr::SepVec;
|
||||||
|
|
||||||
|
type MinusVec<T> = SepVec<T, '-'>;
|
||||||
|
type PlusVec<T> = SepVec<T, '+'>;
|
||||||
|
type MulVec<T> = SepVec<T, '*'>;
|
||||||
|
|
||||||
|
const HELP_MESSAGE: &str = "
|
||||||
|
USAGE:
|
||||||
|
E=10+10*2+4 cargo run --example calc --all-features
|
||||||
|
";
|
||||||
|
|
||||||
|
fn main() -> Result<(), enve::Error> {
|
||||||
|
let res: f32 = enve::get::<PlusVec<MinusVec<MulVec<f32>>>>("E")
|
||||||
|
.map_err(|err| {
|
||||||
|
match err {
|
||||||
|
enve::Error::NotPresent => eprintln!("The expression was not found"),
|
||||||
|
rest => eprintln!("ERROR: {}", rest),
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("{}", HELP_MESSAGE);
|
||||||
|
std::process::exit(0);
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|p| {
|
||||||
|
p.iter()
|
||||||
|
.map(|m| m.iter().product::<f32>())
|
||||||
|
.reduce(|acc, v| acc - v)
|
||||||
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
.sum::<f32>();
|
||||||
|
|
||||||
|
println!("result: {}", res);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,43 +0,0 @@
|
||||||
use std::convert::Infallible;
|
|
||||||
|
|
||||||
use hyper::service::{make_service_fn, service_fn};
|
|
||||||
use hyper::{Body, Request, Response, Server};
|
|
||||||
|
|
||||||
itconfig::config! {
|
|
||||||
hyper {
|
|
||||||
static HOST < (
|
|
||||||
ADDR => "127.0.0.1",
|
|
||||||
":",
|
|
||||||
PORT => 8000,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
|
|
||||||
Ok(Response::new(Body::from("Hello World!")))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
||||||
config::init();
|
|
||||||
pretty_env_logger::init();
|
|
||||||
|
|
||||||
// For every connection, we must make a `Service` to handle all
|
|
||||||
// incoming HTTP requests on said connection.
|
|
||||||
let make_svc = make_service_fn(|_conn| {
|
|
||||||
// This is the `Service` that will handle the connection.
|
|
||||||
// `service_fn` is a helper to convert a function that
|
|
||||||
// returns a Response into a `Service`.
|
|
||||||
async { Ok::<_, Infallible>(service_fn(hello)) }
|
|
||||||
});
|
|
||||||
|
|
||||||
let addr = config::hyper::HOST().parse()?;
|
|
||||||
|
|
||||||
let server = Server::bind(&addr).serve(make_svc);
|
|
||||||
|
|
||||||
println!("Listening on http://{}", addr);
|
|
||||||
|
|
||||||
server.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
# Hyper "hello world"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo run --example hyper
|
|
||||||
```
|
|
||||||
|
|
||||||
# Rocket "hello world"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo run --example roket
|
|
||||||
```
|
|
|
@ -1,22 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate rocket;
|
|
||||||
|
|
||||||
itconfig::config! {
|
|
||||||
rocket {
|
|
||||||
HOST: String => "localhost",
|
|
||||||
PORT: u16 => 9000,
|
|
||||||
BASE_URL => "/",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
fn hello() -> &'static str {
|
|
||||||
"Hello, world!"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[launch]
|
|
||||||
fn rocket() -> _ {
|
|
||||||
config::init();
|
|
||||||
|
|
||||||
rocket::build().mount(config::rocket::BASE_URL(), routes![hello])
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "itconfig_tests"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
|
||||||
edition = "2018"
|
|
||||||
license = "MIT"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
itconfig = { path = '../itconfig', features = ["macro"] }
|
|
||||||
criterion = "0.3.1"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["meta_namespace"]
|
|
||||||
meta_namespace = []
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "main_benches"
|
|
||||||
harness = false
|
|
|
@ -1,81 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "itconfig"
|
|
||||||
version = "1.1.1"
|
|
||||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
|
||||||
description = "Easy build a configs from environment variables and use it in globally."
|
|
||||||
categories = ["config", "web-programming"]
|
|
||||||
keywords = ["config", "env", "configuration", "environment", "macro"]
|
|
||||||
edition = "2018"
|
|
||||||
license = "MIT"
|
|
||||||
repository = "https://github.com/icetemple/itconfig-rs"
|
|
||||||
homepage = "https://github.com/icetemple/itconfig-rs"
|
|
||||||
documentation = "https://docs.rs/itconfig"
|
|
||||||
readme = "../README.md"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["primitives"]
|
|
||||||
|
|
||||||
macro = ["itconfig-macro"]
|
|
||||||
|
|
||||||
primitives = ["numbers", "bool"]
|
|
||||||
numbers = ["int", "uint", "float"]
|
|
||||||
int = ["i8", "i16", "i32", "i64", "i128", "isize"]
|
|
||||||
uint = ["u8", "u16", "u32", "u64", "u128", "usize"]
|
|
||||||
float = ["f32", "f64"]
|
|
||||||
|
|
||||||
i8 = []
|
|
||||||
i16 = []
|
|
||||||
i32 = []
|
|
||||||
i64 = []
|
|
||||||
i128 = []
|
|
||||||
isize = []
|
|
||||||
|
|
||||||
u8 = []
|
|
||||||
u16 = []
|
|
||||||
u32 = []
|
|
||||||
u64 = []
|
|
||||||
u128 = []
|
|
||||||
usize = []
|
|
||||||
|
|
||||||
f32 = []
|
|
||||||
f64 = []
|
|
||||||
|
|
||||||
bool = []
|
|
||||||
|
|
||||||
# deprecated since 1.1
|
|
||||||
json_array = ["serde_json"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde_json = { version = "1", optional = true }
|
|
||||||
itconfig-macro = { version = "1.1", path = "../itconfig-macro", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
# required for examples
|
|
||||||
rocket = "0.5.0-rc.2"
|
|
||||||
hyper = { version = "0.14.4", features = ["full"] }
|
|
||||||
serde_json = "1.0.62"
|
|
||||||
tokio = { version = "1.2.0", features = ["macros", "rt-multi-thread"] }
|
|
||||||
bytes = "1.0.1"
|
|
||||||
futures-util = { version = "0.3.13", default-features = false }
|
|
||||||
pretty_env_logger = "0.4.0"
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
maintenance = { status = "passively-maintained" }
|
|
||||||
|
|
||||||
# https://docs.rs/about
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "hyper"
|
|
||||||
path = "../examples/hyper.rs"
|
|
||||||
required-features = ["macro"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "rocket"
|
|
||||||
path = "../examples/rocket.rs"
|
|
||||||
required-features = ["macro"]
|
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
/// Wrapper under String type.
|
|
||||||
///
|
|
||||||
/// When we read the environment variable, we automatically convert the value
|
|
||||||
/// to EnvString and then convert it to your expected type.
|
|
||||||
///
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
|
||||||
pub struct EnvString(String);
|
|
||||||
|
|
||||||
impl<T> From<T> for EnvString
|
|
||||||
where
|
|
||||||
T: ToEnvString,
|
|
||||||
{
|
|
||||||
fn from(val: T) -> Self {
|
|
||||||
val.to_env_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for EnvString {
|
|
||||||
type Target = String;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for converting value to EnvString.
|
|
||||||
///
|
|
||||||
/// This trait automatically implemented for any type which implements the
|
|
||||||
/// [`Display`] trait. As such, `ToEnvString` shouldn't be implemented directly:
|
|
||||||
/// [`Display`] should be implemented instead, and you get the `ToEnvString`
|
|
||||||
/// implementation for free.
|
|
||||||
///
|
|
||||||
/// [`Display`]: std::fmt::Display
|
|
||||||
pub trait ToEnvString {
|
|
||||||
/// Converts the giving value to a `EnvString`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// basic usage
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use itconfig::{EnvString, ToEnvString};
|
|
||||||
/// let i = 5;
|
|
||||||
/// let five = EnvString::from("5");
|
|
||||||
/// assert_eq!(five, i.to_env_string());
|
|
||||||
/// ```
|
|
||||||
fn to_env_string(&self) -> EnvString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simple and safe type conversions that may fail in a controlled way under
|
|
||||||
/// some circumstances.
|
|
||||||
///
|
|
||||||
/// This trait automatically implemented for all standard primitives. If you
|
|
||||||
/// want to use your custom type in the library you need to implement
|
|
||||||
/// `ToEnvString` and `FromEnvString` manually.
|
|
||||||
pub trait FromEnvString: Sized {
|
|
||||||
/// The type returned in the event of a conversion error.
|
|
||||||
type Err;
|
|
||||||
|
|
||||||
/// Performs the conversion.
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ToEnvString for T
|
|
||||||
where
|
|
||||||
T: std::fmt::Display,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn to_env_string(&self) -> EnvString {
|
|
||||||
EnvString(self.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! from_env_string_numbers_impl {
|
|
||||||
($($ty:ty => $feature:expr),+) => {
|
|
||||||
$(
|
|
||||||
#[cfg(feature = $feature)]
|
|
||||||
impl FromEnvString for $ty {
|
|
||||||
type Err = <$ty as std::str::FromStr>::Err;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
s.0.parse::<Self>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
from_env_string_numbers_impl![
|
|
||||||
i8 => "i8",
|
|
||||||
i16 => "i16",
|
|
||||||
i32 => "i32",
|
|
||||||
i64 => "i64",
|
|
||||||
i128 => "i128",
|
|
||||||
isize => "isize",
|
|
||||||
u8 => "u8",
|
|
||||||
u16 => "u16",
|
|
||||||
u32 => "u32",
|
|
||||||
u64 => "u64",
|
|
||||||
u128 => "u128",
|
|
||||||
usize => "usize",
|
|
||||||
f32 => "f32",
|
|
||||||
f64 => "f64"
|
|
||||||
];
|
|
||||||
|
|
||||||
#[cfg(feature = "bool")]
|
|
||||||
impl FromEnvString for bool {
|
|
||||||
type Err = ();
|
|
||||||
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
match s.to_lowercase().as_str() {
|
|
||||||
"true" | "t" | "yes" | "y" | "on" | "1" => Ok(true),
|
|
||||||
_ => Ok(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromEnvString for String {
|
|
||||||
type Err = ();
|
|
||||||
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
Ok(s.0.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromEnvString for &'static str {
|
|
||||||
type Err = ();
|
|
||||||
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
Ok(Box::leak(s.0.clone().into_boxed_str()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================//
|
|
||||||
// DEPRECATED //
|
|
||||||
//===========================================================================//
|
|
||||||
|
|
||||||
/// Error type for json array implementation
|
|
||||||
#[cfg(feature = "json_array")]
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[deprecated(since = "1.1.0")]
|
|
||||||
pub enum ArrayEnvError {
|
|
||||||
/// Invalid type.
|
|
||||||
InvalidType,
|
|
||||||
|
|
||||||
/// Failed to parse environment variable
|
|
||||||
FailedToParse,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "json_array")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
impl<T> FromEnvString for Vec<T>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
type Err = ArrayEnvError;
|
|
||||||
|
|
||||||
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
serde_json::from_str::<Vec<isize>>(s.trim())
|
|
||||||
.map(|vec| vec.iter().map(|v| v.to_string()).collect::<Vec<String>>())
|
|
||||||
.or_else(|_| serde_json::from_str::<Vec<String>>(s.trim()))
|
|
||||||
.map_err(|_| ArrayEnvError::InvalidType)
|
|
||||||
.and_then(|vec| {
|
|
||||||
vec.iter()
|
|
||||||
.map(|v| {
|
|
||||||
FromEnvString::from_env_string(&v.to_env_string())
|
|
||||||
.map_err(|_| ArrayEnvError::FailedToParse)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<T>, _>>()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
/// The error type for operations interacting with environment variables
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum EnvError {
|
|
||||||
/// The specified environment variable was not present in the current process's environment.
|
|
||||||
MissingVariable(String),
|
|
||||||
|
|
||||||
/// Failed to parse the specified environment variable.
|
|
||||||
FailedToParse(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for EnvError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match &self {
|
|
||||||
EnvError::MissingVariable(env_name) => {
|
|
||||||
write!(f, r#"Environment variable "{}" is missing"#, env_name)
|
|
||||||
}
|
|
||||||
EnvError::FailedToParse(env_name) => {
|
|
||||||
write!(f, r#"Failed to parse environment variable "{}""#, env_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for EnvError {}
|
|
|
@ -1,240 +0,0 @@
|
||||||
use crate::envstr::*;
|
|
||||||
use crate::error::*;
|
|
||||||
use crate::utils::*;
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
/// Same as get_env but returns Option enum instead Result
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::maybe_get_env;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// env::set_var("HOST", "https://example.com");
|
|
||||||
///
|
|
||||||
/// let host: Option<&'static str> = maybe_get_env("HOST");
|
|
||||||
/// let not_existence_host: Option<&'static str> = maybe_get_env("NOT_EXISTENCE_HOST");
|
|
||||||
///
|
|
||||||
/// assert_eq!(host, Some("https://example.com"));
|
|
||||||
/// assert_eq!(not_existence_host, None);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn maybe_get_env<T>(env_name: &str) -> Option<T>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_env(env_name).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_env`, but it unwraps result with panic on error.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if environment variable is missing or cannot parse variable to
|
|
||||||
/// expected type
|
|
||||||
///
|
|
||||||
pub fn get_env_or_panic<T>(env_name: &str) -> T
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_env(env_name).unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to read environment variable and parse to expected type. You may to put to argument
|
|
||||||
/// any type with `FromEnvString` trait.
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_env;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// env::set_var("DEBUG", "true");
|
|
||||||
///
|
|
||||||
/// let result: bool = get_env("DEBUG").unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(result, true);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_env<T>(env_name: &str) -> Result<T, EnvError>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_env_or(env_name, |_| {
|
|
||||||
Err(EnvError::MissingVariable(env_name.to_string()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_env_or_panic`, but you can pass default value for
|
|
||||||
/// environment variable with `ToEnvString` trait.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if cannot parse variable to expected type
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_env_or_default;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let result: bool = get_env_or_default("TESTING", "true");
|
|
||||||
/// assert_eq!(result, true);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_env_or_default<T, D>(env_name: &str, default: D) -> T
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
D: ToEnvString,
|
|
||||||
{
|
|
||||||
get_env_or(env_name, |_| Ok(default.to_env_string())).unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_env_or_default`, but the default value will be set to environment
|
|
||||||
/// variable, if env variable is missed.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if cannot parse variable to expected type
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_env_or_set_default;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let result: bool = get_env_or_set_default("TESTING", "true");
|
|
||||||
/// assert_eq!(result, true);
|
|
||||||
///
|
|
||||||
/// let var = env::var("TESTING").unwrap();
|
|
||||||
/// assert_eq!(var, "true");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_env_or_set_default<T, D>(env_name: &str, default: D) -> T
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
D: ToEnvString,
|
|
||||||
{
|
|
||||||
get_env_or(env_name, |_| {
|
|
||||||
let val = default.to_env_string();
|
|
||||||
env::set_var(env_name, val.as_str());
|
|
||||||
Ok(val)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function returns env variable as `EnvString` structure. You can pass callback for custom
|
|
||||||
/// default expression. Callback should return `EnvString` value or `EnvError`
|
|
||||||
pub fn get_env_or<T, F>(env_name: &str, cb: F) -> Result<T, EnvError>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
F: FnOnce(env::VarError) -> Result<EnvString, EnvError>,
|
|
||||||
{
|
|
||||||
env::var(env_name)
|
|
||||||
.map(|s| s.to_env_string())
|
|
||||||
.or_else(cb)
|
|
||||||
.and_then(|env_str| parse_env_variable(env_name, env_str))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Environment variable \"TEST_CASE_1\" is missing")]
|
|
||||||
fn get_missing_env() {
|
|
||||||
get_env_or_panic::<String>("TEST_CASE_1");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_2\"")]
|
|
||||||
fn get_env_with_invalid_value() {
|
|
||||||
let env_name = "TEST_CASE_2";
|
|
||||||
env::set_var(&env_name, "30r");
|
|
||||||
get_env_or_panic::<u32>(env_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_missing_env() {
|
|
||||||
let env_name = String::from("TEST_CASE_3");
|
|
||||||
let env_val = get_env::<String>(&env_name);
|
|
||||||
assert_eq!(env_val, Err(EnvError::MissingVariable(env_name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_env_with_invalid_value() {
|
|
||||||
let env_name = String::from("TEST_CASE_4");
|
|
||||||
env::set_var(&env_name, "30r");
|
|
||||||
let env_val = get_env::<u32>(&env_name);
|
|
||||||
assert_eq!(env_val, Err(EnvError::FailedToParse(env_name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_env_successfully() {
|
|
||||||
env::set_var("TEST_CASE_5", "30");
|
|
||||||
let env_var = get_env("TEST_CASE_5");
|
|
||||||
assert_eq!(env_var, Ok(30));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_missing_env_with_default_value() {
|
|
||||||
let flag: bool = get_env_or_default("TEST_CASE_6", "true");
|
|
||||||
assert!(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_7\"")]
|
|
||||||
fn get_invalid_env_with_default_value() {
|
|
||||||
env::set_var("TEST_CASE_7", "30r");
|
|
||||||
get_env_or_default::<u32, _>("TEST_CASE_7", 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_8\"")]
|
|
||||||
fn get_env_with_invalid_default_value() {
|
|
||||||
get_env_or_default::<u32, _>("TEST_CASE_8", "30r");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_env_with_default_successfully() {
|
|
||||||
env::set_var("TEST_CASE_9", "10");
|
|
||||||
let env_val: u32 = get_env_or_default("TEST_CASE_9", 30);
|
|
||||||
assert_eq!(env_val, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_missing_env_with_set_default_value() {
|
|
||||||
let flag: bool = get_env_or_set_default("TEST_CASE_10", "true");
|
|
||||||
assert!(flag);
|
|
||||||
|
|
||||||
let env_var = env::var("TEST_CASE_10");
|
|
||||||
assert_eq!(env_var, Ok(String::from("true")))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_optional_env() {
|
|
||||||
env::set_var("TEST_CASE_11", "something");
|
|
||||||
let something: Option<&'static str> = maybe_get_env("TEST_CASE_11");
|
|
||||||
assert_eq!(something, Some("something"));
|
|
||||||
|
|
||||||
let nothing: Option<&'static str> = maybe_get_env("TEST_CASE_11_NONE");
|
|
||||||
assert_eq!(nothing, None);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,304 +0,0 @@
|
||||||
use crate::envstr::*;
|
|
||||||
use crate::error::*;
|
|
||||||
use crate::utils::*;
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
/// Same as get_vec_env but returns Option enum instead Result
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::*;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// #[derive(Debug, PartialEq, Eq)]
|
|
||||||
/// enum PaymentPlatform {
|
|
||||||
/// PayPal,
|
|
||||||
/// Stripe,
|
|
||||||
/// SomethingElse,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl FromEnvString for PaymentPlatform {
|
|
||||||
/// type Err = &'static str;
|
|
||||||
///
|
|
||||||
/// fn from_env_string(envstr: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
/// match envstr.to_lowercase().as_str() {
|
|
||||||
/// "paypal" => Ok(Self::PayPal),
|
|
||||||
/// "stripe" => Ok(Self::Stripe),
|
|
||||||
/// "smth" => Ok(Self::SomethingElse),
|
|
||||||
/// _ => Err("Unsupported payment platform"),
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// env::set_var("PAYMENT_PLATFORMS", "paypal,stripe");
|
|
||||||
///
|
|
||||||
/// let payment_platforms: Option<Vec<PaymentPlatform>> = maybe_get_vec_env("PAYMENT_PLATFORMS", ",");
|
|
||||||
/// assert_eq!(
|
|
||||||
/// payment_platforms,
|
|
||||||
/// Some(vec![PaymentPlatform::PayPal, PaymentPlatform::Stripe])
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn maybe_get_vec_env<T>(env_name: &str, sep: &'static str) -> Option<Vec<T>>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_vec_env(env_name, sep).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_vec_env`, but it unwraps result with panic on error.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if environment variable is missing or cannot parse variable to
|
|
||||||
/// expected type
|
|
||||||
///
|
|
||||||
pub fn get_vec_env_or_panic<T>(env_name: &str, sep: &'static str) -> Vec<T>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_vec_env(env_name, sep).unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to read environment variable, split by separator and parse each item to expected
|
|
||||||
/// type.
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_vec_env;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// env::set_var("DEBUG", "true");
|
|
||||||
///
|
|
||||||
/// let result: Vec<bool> = get_vec_env("DEBUG", ",").unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(result, vec![true]);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_vec_env<T>(env_name: &str, sep: &str) -> Result<Vec<T>, EnvError>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
get_vec_env_or(env_name, sep, |_| {
|
|
||||||
Err(EnvError::MissingVariable(env_name.to_string()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_vec_env_or_panic`, but you can pass default value for
|
|
||||||
/// environment variable with `ToEnvString` trait.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if cannot parse variable to expected type
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_vec_env_or_default;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let result: Vec<bool> = get_vec_env_or_default("TESTING", ",", vec!["true"]);
|
|
||||||
/// assert_eq!(result, vec![true]);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_vec_env_or_default<T, D>(env_name: &str, sep: &str, default: Vec<D>) -> Vec<T>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
D: ToEnvString,
|
|
||||||
{
|
|
||||||
get_vec_env_or(env_name, sep, |_| Ok(vec_to_env_strings(default))).unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is similar as `get_vec_env_or_default`, but the default value will be set to environment
|
|
||||||
/// variable, if env variable is missed.
|
|
||||||
///
|
|
||||||
/// Panics
|
|
||||||
/// ------
|
|
||||||
/// Application will panic if cannot parse variable to expected type
|
|
||||||
///
|
|
||||||
/// Example
|
|
||||||
/// -------
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate itconfig;
|
|
||||||
/// # use itconfig::get_vec_env_or_set_default;
|
|
||||||
/// use std::env;
|
|
||||||
///
|
|
||||||
/// fn main () {
|
|
||||||
/// let result: Vec<bool> = get_vec_env_or_set_default("TESTING", ",", vec!["true"]);
|
|
||||||
/// assert_eq!(result, vec![true]);
|
|
||||||
///
|
|
||||||
/// let var = env::var("TESTING").unwrap();
|
|
||||||
/// assert_eq!(var, "true");
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn get_vec_env_or_set_default<T, D>(env_name: &str, sep: &str, default: Vec<D>) -> Vec<T>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
D: ToEnvString,
|
|
||||||
{
|
|
||||||
get_vec_env_or(env_name, sep, |_| {
|
|
||||||
let default_env_strings = vec_to_env_strings(default);
|
|
||||||
let env_val = join(&default_env_strings, sep);
|
|
||||||
env::set_var(env_name, env_val.as_str());
|
|
||||||
Ok(default_env_strings)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(make_panic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function returns env variable as `EnvString` structure. You can pass callback for custom
|
|
||||||
/// default expression. Callback should return `EnvString` value or `EnvError`
|
|
||||||
pub fn get_vec_env_or<T, F>(env_name: &str, sep: &str, cb: F) -> Result<Vec<T>, EnvError>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
F: FnOnce(env::VarError) -> Result<Vec<EnvString>, EnvError>,
|
|
||||||
{
|
|
||||||
env::var(env_name)
|
|
||||||
.map(|s| {
|
|
||||||
s.split(sep)
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.to_env_string())
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.or_else(cb)
|
|
||||||
.and_then(|items| {
|
|
||||||
items
|
|
||||||
.into_iter()
|
|
||||||
.map(|env_str| parse_env_variable(env_name, env_str))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const SEP: &str = ",";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Environment variable \"TEST_CASE_VEC_1\" is missing")]
|
|
||||||
fn get_missing_vec_env() {
|
|
||||||
let _: Vec<&'static str> = get_vec_env_or_panic("TEST_CASE_VEC_1", SEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_VEC_2\"")]
|
|
||||||
fn get_vec_env_with_invalid_value() {
|
|
||||||
let env_name = "TEST_CASE_VEC_2";
|
|
||||||
env::set_var(&env_name, "30r");
|
|
||||||
let _: Vec<u32> = get_vec_env_or_panic(env_name, SEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_missing_vec_env() {
|
|
||||||
let env_name = String::from("TEST_CASE_VEC_3");
|
|
||||||
let env_val = get_vec_env::<String>(&env_name, SEP);
|
|
||||||
assert_eq!(env_val, Err(EnvError::MissingVariable(env_name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_vec_env_with_invalid_value() {
|
|
||||||
let env_name = String::from("TEST_CASE_VEC_4");
|
|
||||||
env::set_var(&env_name, "30r");
|
|
||||||
let env_val = get_vec_env::<u32>(&env_name, SEP);
|
|
||||||
assert_eq!(env_val, Err(EnvError::FailedToParse(env_name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_result_of_vec_env_successfully() {
|
|
||||||
env::set_var("TEST_CASE_VEC_5", "30");
|
|
||||||
let env_var = get_vec_env("TEST_CASE_VEC_5", SEP);
|
|
||||||
assert_eq!(env_var, Ok(vec![30]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_missing_vec_env_with_default_value() {
|
|
||||||
let flag: Vec<bool> = get_vec_env_or_default("TEST_CASE_VEC_6", SEP, vec!["true"]);
|
|
||||||
assert_eq!(flag, vec![true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_VEC_7\"")]
|
|
||||||
fn get_invalid_vec_env_with_default_value() {
|
|
||||||
env::set_var("TEST_CASE_VEC_7", "30r");
|
|
||||||
get_vec_env_or_default::<u32, _>("TEST_CASE_VEC_7", SEP, vec![30]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "Failed to parse environment variable \"TEST_CASE_VEC_8\"")]
|
|
||||||
fn get_vec_env_with_invalid_default_value() {
|
|
||||||
get_vec_env_or_default::<u32, _>("TEST_CASE_VEC_8", SEP, vec!["30r"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_vec_env_with_default_successfully() {
|
|
||||||
env::set_var("TEST_CASE_VEC_9", "10");
|
|
||||||
let env_val: Vec<u32> = get_vec_env_or_default("TEST_CASE_VEC_9", SEP, vec![30]);
|
|
||||||
assert_eq!(env_val, vec![10])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_missing_vec_env_with_set_default_value() {
|
|
||||||
let flag: Vec<bool> = get_vec_env_or_set_default("TEST_CASE_VEC_10", SEP, vec!["true"]);
|
|
||||||
assert_eq!(flag, vec![true]);
|
|
||||||
|
|
||||||
let env_var = env::var("TEST_CASE_VEC_10");
|
|
||||||
assert_eq!(env_var, Ok(String::from("true")))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_optional_vec_env() {
|
|
||||||
env::set_var("TEST_CASE_VEC_11", "something");
|
|
||||||
let something: Option<Vec<&'static str>> = maybe_get_vec_env("TEST_CASE_VEC_11", SEP);
|
|
||||||
assert_eq!(something, Some(vec!["something"]));
|
|
||||||
|
|
||||||
let nothing: Option<Vec<&'static str>> = maybe_get_vec_env("TEST_CASE_VEC_11_NONE", SEP);
|
|
||||||
assert_eq!(nothing, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_custom_type_from_vec_env() {
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
enum PaymentPlatform {
|
|
||||||
PayPal,
|
|
||||||
Stripe,
|
|
||||||
SomethingElse,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromEnvString for PaymentPlatform {
|
|
||||||
type Err = &'static str;
|
|
||||||
|
|
||||||
fn from_env_string(envstr: &EnvString) -> Result<Self, Self::Err> {
|
|
||||||
match envstr.to_lowercase().as_str() {
|
|
||||||
"paypal" => Ok(Self::PayPal),
|
|
||||||
"stripe" => Ok(Self::Stripe),
|
|
||||||
"smth" => Ok(Self::SomethingElse),
|
|
||||||
_ => Err("Unsupported payment platform"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env::set_var("TEST_CASE_VEC_12", "paypal,stripe");
|
|
||||||
let something: Option<Vec<PaymentPlatform>> = maybe_get_vec_env("TEST_CASE_VEC_12", SEP);
|
|
||||||
assert_eq!(
|
|
||||||
something,
|
|
||||||
Some(vec![PaymentPlatform::PayPal, PaymentPlatform::Stripe])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
use crate::{EnvError, EnvString, FromEnvString, ToEnvString};
|
|
||||||
|
|
||||||
pub(crate) fn parse_env_variable<T>(env_name: &str, env_str: EnvString) -> Result<T, EnvError>
|
|
||||||
where
|
|
||||||
T: FromEnvString,
|
|
||||||
{
|
|
||||||
FromEnvString::from_env_string(&env_str)
|
|
||||||
.map_err(|_| EnvError::FailedToParse(env_name.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn make_panic<T>(e: EnvError) -> T {
|
|
||||||
panic!("{}", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn join(env_strings: &[EnvString], sep: &str) -> String {
|
|
||||||
env_strings
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.fold(String::new(), |mut res, (i, item)| {
|
|
||||||
if i > 0 {
|
|
||||||
res.push_str(sep);
|
|
||||||
}
|
|
||||||
res.push_str(item);
|
|
||||||
res
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn vec_to_env_strings<T>(values: Vec<T>) -> Vec<EnvString>
|
|
||||||
where
|
|
||||||
T: ToEnvString,
|
|
||||||
{
|
|
||||||
values.into_iter().map(EnvString::from).collect()
|
|
||||||
}
|
|
238
src/core.rs
Normal file
238
src/core.rs
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
use crate::error::Error;
|
||||||
|
use estring::EString;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
pub fn get_or_set_default<R>(env_name: &str, default: R) -> Result<R, Error>
|
||||||
|
where
|
||||||
|
R: TryFrom<EString> + std::fmt::Display,
|
||||||
|
{
|
||||||
|
get::<R>(env_name).or_else(|err| match err {
|
||||||
|
Error::NotPresent => sset(env_name, &default).parse().map_err(Error::from),
|
||||||
|
_ => Err(err),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<R>(env_name: &str) -> Result<R, Error>
|
||||||
|
where
|
||||||
|
R: TryFrom<EString>,
|
||||||
|
{
|
||||||
|
sget(env_name).and_then(|v| v.parse().map_err(Error::from))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sget(env_name: &str) -> Result<EString, Error> {
|
||||||
|
std::env::var(env_name)
|
||||||
|
.map_err(Error::from)
|
||||||
|
.map(EString::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sset<V>(env_name: &str, value: V) -> EString
|
||||||
|
where
|
||||||
|
V: std::fmt::Display,
|
||||||
|
{
|
||||||
|
let val = value.to_string();
|
||||||
|
std::env::set_var(env_name, &val);
|
||||||
|
val.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct TestCase<const N: u8>;
|
||||||
|
|
||||||
|
impl<const N: u8> std::fmt::Display for TestCase<N> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "test_case_{}", N)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_add_env_variable_to_process() {
|
||||||
|
let en = TestCase::<0>.to_string();
|
||||||
|
sset(&en, "hello");
|
||||||
|
match std::env::var(&en) {
|
||||||
|
Ok(var) => assert_eq!(&var, "hello"),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_variable() {
|
||||||
|
let en = TestCase::<1>.to_string();
|
||||||
|
std::env::set_var(&en, "hello");
|
||||||
|
match get::<&str>(&en) {
|
||||||
|
Ok(res) => assert_eq!(res, "hello"),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_no_present_error() {
|
||||||
|
let en = TestCase::<2>.to_string();
|
||||||
|
match get::<&str>(&en) {
|
||||||
|
Err(Error::NotPresent) => {}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_set_default_if_var_is_no_present() {
|
||||||
|
let en = TestCase::<3>.to_string();
|
||||||
|
let orig = "hello";
|
||||||
|
match get_or_set_default(&en, orig) {
|
||||||
|
Ok(res) => {
|
||||||
|
assert_eq!(res, orig);
|
||||||
|
assert_eq!(std::env::var(&en).unwrap(), orig);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "number")]
|
||||||
|
mod numbers {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_parsed_num() {
|
||||||
|
let en = TestCase::<4>.to_string();
|
||||||
|
std::env::set_var(&en, "-10");
|
||||||
|
match get::<i32>(&en) {
|
||||||
|
Ok(res) => assert_eq!(res, -10),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_parse_error() {
|
||||||
|
let en = TestCase::<5>.to_string();
|
||||||
|
std::env::set_var(&en, "-10");
|
||||||
|
match get::<u32>(&en) {
|
||||||
|
Err(Error::Parse(orig)) => {
|
||||||
|
assert_eq!(orig, String::from("-10"))
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_set_default_num_if_var_is_no_present() {
|
||||||
|
let en = TestCase::<6>.to_string();
|
||||||
|
let orig = 10;
|
||||||
|
match get_or_set_default(&en, orig) {
|
||||||
|
Ok(res) => {
|
||||||
|
assert_eq!(res, orig);
|
||||||
|
assert_eq!(std::env::var(&en).unwrap(), "10");
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bool")]
|
||||||
|
mod boolean {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_bool_variable() {
|
||||||
|
let en = TestCase::<7>.to_string();
|
||||||
|
|
||||||
|
[
|
||||||
|
("1", true),
|
||||||
|
("y", true),
|
||||||
|
("yes", true),
|
||||||
|
("true", true),
|
||||||
|
("t", true),
|
||||||
|
("on", true),
|
||||||
|
("false", false),
|
||||||
|
("f", false),
|
||||||
|
("0", false),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.for_each(|(val, expected)| {
|
||||||
|
let mut en = en.clone();
|
||||||
|
en.push_str(val.as_ref());
|
||||||
|
|
||||||
|
std::env::set_var(&en, val);
|
||||||
|
match get::<bool>(&en) {
|
||||||
|
Ok(res) => assert_eq!(res, *expected),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "vec")]
|
||||||
|
mod vector {
|
||||||
|
use super::*;
|
||||||
|
use crate::estr::{CommaVec, SemiVec, SepVec};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_var_as_vector() {
|
||||||
|
let en = TestCase::<8>.to_string();
|
||||||
|
|
||||||
|
std::env::set_var(&en, "1,2,3,4,5");
|
||||||
|
match get::<CommaVec<i32>>(&en) {
|
||||||
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_trim_identations_before_parsing() {
|
||||||
|
let en = TestCase::<9>.to_string();
|
||||||
|
|
||||||
|
let input = "
|
||||||
|
1 , 2, 3,
|
||||||
|
4,5";
|
||||||
|
|
||||||
|
std::env::set_var(&en, input);
|
||||||
|
match get::<CommaVec<i32>>(&en) {
|
||||||
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_vector_of_vectors() {
|
||||||
|
let en = TestCase::<10>.to_string();
|
||||||
|
|
||||||
|
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
||||||
|
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
||||||
|
Ok(res) => assert_eq!(
|
||||||
|
res,
|
||||||
|
SemiVec::from(vec![
|
||||||
|
CommaVec::from(vec![1, 2]),
|
||||||
|
CommaVec::from(vec![3, 4, 5]),
|
||||||
|
CommaVec::from(vec![6, 7])
|
||||||
|
])
|
||||||
|
),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_throw_parse_vec_error() {
|
||||||
|
let en = TestCase::<11>.to_string();
|
||||||
|
std::env::set_var(&en, "1,2,3,4,5");
|
||||||
|
match get::<SepVec<i32, '+'>>(&en) {
|
||||||
|
Err(Error::Parse(orig)) => {
|
||||||
|
assert_eq!(orig, String::from("1,2,3,4,5"))
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_set_default_vector_if_var_is_no_present() {
|
||||||
|
let en = TestCase::<12>.to_string();
|
||||||
|
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
||||||
|
match get_or_set_default(&en, orig.clone()) {
|
||||||
|
Ok(res) => {
|
||||||
|
assert_eq!(res, orig);
|
||||||
|
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
src/error.rs
Normal file
53
src/error.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::env::VarError;
|
||||||
|
use std::error;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// The error type for operations interacting with environment variables
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The specified environment variable was not present in the current process's environment.
|
||||||
|
NotPresent,
|
||||||
|
|
||||||
|
/// Failed to parse the specified environment variable.
|
||||||
|
Parse(String),
|
||||||
|
|
||||||
|
/// The specified environment variable was found, but it did not contain
|
||||||
|
/// valid unicode data. The found data is returned as a payload of this
|
||||||
|
/// variant.
|
||||||
|
Invalid(OsString),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use Error::*;
|
||||||
|
match &self {
|
||||||
|
NotPresent => f.write_str("The specified env variable was not present"),
|
||||||
|
Invalid(inner) => write!(
|
||||||
|
f,
|
||||||
|
"The specified env variable was found, but it did not valid: '{:?}'",
|
||||||
|
inner,
|
||||||
|
),
|
||||||
|
Parse(env_name) => {
|
||||||
|
write!(f, r#"Failed to parse environment variable "{}""#, env_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {}
|
||||||
|
|
||||||
|
impl From<VarError> for Error {
|
||||||
|
fn from(err: VarError) -> Self {
|
||||||
|
match err {
|
||||||
|
VarError::NotPresent => Error::NotPresent,
|
||||||
|
VarError::NotUnicode(inner) => Error::Invalid(inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<estring::ParseError> for Error {
|
||||||
|
fn from(err: estring::ParseError) -> Self {
|
||||||
|
Error::Parse(err.clone())
|
||||||
|
}
|
||||||
|
}
|
6
src/estr.rs
Normal file
6
src/estr.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#[cfg(feature = "vec")]
|
||||||
|
pub mod vec;
|
||||||
|
#[cfg(feature = "vec")]
|
||||||
|
pub use vec::{CommaVec, SemiVec};
|
||||||
|
|
||||||
|
pub use estring::core::*;
|
7
src/estr/vec.rs
Normal file
7
src/estr/vec.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use estring::SepVec;
|
||||||
|
|
||||||
|
const COMMA: char = ',';
|
||||||
|
const SEMI: char = ';';
|
||||||
|
|
||||||
|
pub type CommaVec<T> = SepVec<T, COMMA>;
|
||||||
|
pub type SemiVec<T> = SepVec<T, SEMI>;
|
|
@ -1,4 +1,4 @@
|
||||||
//! # itconfig
|
//! # enve
|
||||||
//!
|
//!
|
||||||
//! Simple configuration with macro for rust application.
|
//! Simple configuration with macro for rust application.
|
||||||
//!
|
//!
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
//!
|
//!
|
||||||
//! These macros require a Rust compiler version 1.31 or newer.
|
//! These macros require a Rust compiler version 1.31 or newer.
|
||||||
//!
|
//!
|
||||||
//! Add `itconfig = { version = "1.0", features = ["macro"] }` as a dependency in `Cargo.toml`.
|
//! Add `enve = { version = "1.0", features = ["macro"] }` as a dependency in `Cargo.toml`.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! `Cargo.toml` example:
|
//! `Cargo.toml` example:
|
||||||
|
@ -28,14 +28,14 @@
|
||||||
//! authors = ["Me <user@rust-lang.org>"]
|
//! authors = ["Me <user@rust-lang.org>"]
|
||||||
//!
|
//!
|
||||||
//! [dependencies]
|
//! [dependencies]
|
||||||
//! itconfig = { version = "1.0", features = ["macro"] }
|
//! enve = { version = "1.0", features = ["macro"] }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! ## Basic usage
|
//! ## Basic usage
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use itconfig::config;
|
//! use enve::config;
|
||||||
//! use std::env;
|
//! use std::env;
|
||||||
//! //use dotenv::dotenv;
|
//! //use dotenv::dotenv;
|
||||||
//!
|
//!
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
//! Macro is an optional feature, disabled by default. You can use this library without macro.
|
//! Macro is an optional feature, disabled by default. You can use this library without macro.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use itconfig::*;
|
//! use enve::*;
|
||||||
//! use std::env;
|
//! use std::env;
|
||||||
//! // use dotenv::dotenv;
|
//! // use dotenv::dotenv;
|
||||||
//!
|
//!
|
||||||
|
@ -142,24 +142,22 @@
|
||||||
unused_imports,
|
unused_imports,
|
||||||
unused_qualifications
|
unused_qualifications
|
||||||
)]
|
)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
// Clippy lints
|
// Clippy lints
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all)]
|
||||||
#![allow(clippy::needless_doctest_main)]
|
#![allow(clippy::needless_doctest_main)]
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
mod envstr;
|
mod core;
|
||||||
mod error;
|
mod error;
|
||||||
mod get_env;
|
pub mod estr;
|
||||||
mod get_vec_env;
|
|
||||||
pub(crate) mod utils;
|
|
||||||
|
|
||||||
pub use self::envstr::*;
|
pub use self::core::*;
|
||||||
pub use self::error::*;
|
pub use self::core::{get, get_or_set_default, sget, sset};
|
||||||
pub use self::get_env::*;
|
pub use self::error::Error;
|
||||||
pub use self::get_vec_env::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "macro")]
|
#[cfg(feature = "macro")]
|
||||||
extern crate itconfig_macro;
|
extern crate enve_mod;
|
||||||
#[cfg(feature = "macro")]
|
#[cfg(feature = "macro")]
|
||||||
pub use itconfig_macro::*;
|
pub use enve_mod::*;
|
Reference in a new issue