Skip to content

Commit

Permalink
Merge pull request #217 from dlo9/master
Browse files Browse the repository at this point in the history
Preserve map ordering
  • Loading branch information
matthiasbeyer committed Aug 20, 2021
2 parents 74a0a80 + 9075ca9 commit 0d3a5c3
Show file tree
Hide file tree
Showing 48 changed files with 375 additions and 183 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/msrv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,23 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features

- name: Run cargo test (nightly)
if: matrix.rust == '1.46.0'
continue-on-error: true
uses: actions-rs/cargo@v1
with:
command: test
args: --tests
args: --tests --all-features

- name: Run cargo test (nightly)
if: matrix.rust == 'nightly'
continue-on-error: true
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features

fmt:
needs: [check]
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ yaml = ["yaml-rust"]
hjson = ["serde-hjson"]
ini = ["rust-ini"]
json5 = ["json5_rs"]
preserve_order = ["indexmap", "toml/preserve_order", "serde_json/preserve_order", "ron/indexmap"]

[dependencies]
async-trait = "0.1.50"
Expand All @@ -35,6 +36,7 @@ serde-hjson = { version = "0.9", default-features = false, optional = true }
rust-ini = { version = "0.17", optional = true }
ron = { version = "0.6", optional = true }
json5_rs = { version = "0.3", optional = true, package = "json5" }
indexmap = { version = "1.7.0", features = ["serde-1"], optional = true}

[dev-dependencies]
serde_derive = "1.0.8"
Expand Down
6 changes: 3 additions & 3 deletions examples/async_source/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashMap, error::Error};
use std::error::Error;

use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat};
use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat, Map};

use async_trait::async_trait;
use futures::{select, FutureExt};
Expand Down Expand Up @@ -56,7 +56,7 @@ struct HttpSource {

#[async_trait]
impl AsyncSource for HttpSource {
async fn collect(&self) -> Result<HashMap<String, config::Value>, ConfigError> {
async fn collect(&self) -> Result<Map<String, config::Value>, ConfigError> {
reqwest::get(&self.uri)
.await
.map_err(|e| ConfigError::Foreign(Box::new(e)))? // error conversion is possible from custom AsyncSource impls
Expand Down
14 changes: 7 additions & 7 deletions examples/glob/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::path::Path;
use std::collections::HashMap;
use std::collections::Map;
use config::*;
use glob::glob;

Expand All @@ -14,9 +14,9 @@ fn main() {
.merge(File::from(Path::new("conf/05-some.yml"))).unwrap()
.merge(File::from(Path::new("conf/99-extra.json"))).unwrap();

// Print out our settings (as a HashMap)
// Print out our settings (as a Map)
println!("\n{:?} \n\n-----------",
settings.try_into::<HashMap<String, String>>().unwrap());
settings.try_into::<Map<String, String>>().unwrap());

// Option 2
// --------
Expand All @@ -28,9 +28,9 @@ fn main() {
File::from(Path::new("conf/99-extra.json"))])
.unwrap();

// Print out our settings (as a HashMap)
// Print out our settings (as a Map)
println!("\n{:?} \n\n-----------",
settings.try_into::<HashMap<String, String>>().unwrap());
settings.try_into::<Map<String, String>>().unwrap());

// Option 3
// --------
Expand All @@ -43,7 +43,7 @@ fn main() {
.collect::<Vec<_>>())
.unwrap();

// Print out our settings (as a HashMap)
// Print out our settings (as a Map)
println!("\n{:?} \n\n-----------",
settings.try_into::<HashMap<String, String>>().unwrap());
settings.try_into::<Map<String, String>>().unwrap());
}
6 changes: 3 additions & 3 deletions examples/simple/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::Map;

fn main() {
let mut settings = config::Config::default();
Expand All @@ -9,7 +9,7 @@ fn main() {
// Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
.merge(config::Environment::with_prefix("APP")).unwrap();

// Print out our settings (as a HashMap)
// Print out our settings (as a Map)
println!("{:?}",
settings.try_into::<HashMap<String, String>>().unwrap());
settings.try_into::<Map<String, String>>().unwrap());
}
4 changes: 2 additions & 2 deletions examples/watch/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use config::*;
use std::collections::HashMap;
use std::collections::Map;
use std::sync::RwLock;
use notify::{RecommendedWatcher, DebouncedEvent, Watcher, RecursiveMode};
use std::sync::mpsc::channel;
Expand All @@ -20,7 +20,7 @@ fn show() {
.read()
.unwrap()
.clone()
.try_into::<HashMap<String, String>>()
.try_into::<Map<String, String>>()
.unwrap());
}

Expand Down
23 changes: 12 additions & 11 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::iter::IntoIterator;
use std::str::FromStr;
use std::{collections::HashMap, iter::IntoIterator};

use crate::error::Result;
use crate::map::Map;
use crate::source::AsyncSource;
use crate::{config::Config, path::Expression, source::Source, value::Value};

Expand Down Expand Up @@ -87,8 +88,8 @@ use crate::{config::Config, path::Expression, source::Source, value::Value};
/// ```
#[derive(Debug, Clone, Default)]
pub struct ConfigBuilder<St: BuilderState> {
defaults: HashMap<Expression, Value>,
overrides: HashMap<Expression, Value>,
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
state: St,
}

Expand Down Expand Up @@ -120,8 +121,8 @@ pub struct DefaultState {
/// Refer to [`ConfigBuilder`] for similar API sample usage or to the examples folder of the crate, where such a source is implemented.
#[derive(Debug, Clone, Default)]
pub struct AsyncConfigBuilder {
defaults: HashMap<Expression, Value>,
overrides: HashMap<Expression, Value>,
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
sources: Vec<SourceType>,
}

Expand Down Expand Up @@ -244,11 +245,11 @@ impl ConfigBuilder<DefaultState> {
}

fn build_internal(
defaults: HashMap<Expression, Value>,
overrides: HashMap<Expression, Value>,
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
sources: &[Box<dyn Source + Send + Sync>],
) -> Result<Config> {
let mut cache: Value = HashMap::<String, Value>::new().into();
let mut cache: Value = Map::<String, Value>::new().into();

// Add defaults
for (key, val) in defaults.into_iter() {
Expand Down Expand Up @@ -322,11 +323,11 @@ impl ConfigBuilder<AsyncState> {
}

async fn build_internal(
defaults: HashMap<Expression, Value>,
overrides: HashMap<Expression, Value>,
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
sources: &[SourceType],
) -> Result<Config> {
let mut cache: Value = HashMap::<String, Value>::new().into();
let mut cache: Value = Map::<String, Value>::new().into();

// Add defaults
for (key, val) in defaults.into_iter() {
Expand Down
12 changes: 6 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::collections::HashMap;
use std::fmt::Debug;

use crate::builder::{ConfigBuilder, DefaultState};
use serde::de::Deserialize;
use serde::ser::Serialize;

use crate::error::*;
use crate::map::Map;
use crate::path;
use crate::ser::ConfigSerializer;
use crate::source::Source;
Expand All @@ -16,8 +16,8 @@ use crate::value::{Table, Value};
/// them according to the source's priority.
#[derive(Clone, Debug)]
pub struct Config {
defaults: HashMap<path::Expression, Value>,
overrides: HashMap<path::Expression, Value>,
defaults: Map<path::Expression, Value>,
overrides: Map<path::Expression, Value>,
sources: Vec<Box<dyn Source + Send + Sync>>,

/// Root of the cached configuration.
Expand Down Expand Up @@ -83,7 +83,7 @@ impl Config {
#[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
pub fn refresh(&mut self) -> Result<&mut Config> {
self.cache = {
let mut cache: Value = HashMap::<String, Value>::new().into();
let mut cache: Value = Map::<String, Value>::new().into();

// Add defaults
for (key, val) in self.defaults.iter() {
Expand Down Expand Up @@ -181,7 +181,7 @@ impl Config {
self.get(key).and_then(Value::into_bool)
}

pub fn get_table(&self, key: &str) -> Result<HashMap<String, Value>> {
pub fn get_table(&self, key: &str) -> Result<Map<String, Value>> {
self.get(key).and_then(Value::into_table)
}

Expand Down Expand Up @@ -212,7 +212,7 @@ impl Source for Config {
Box::new((*self).clone())
}

fn collect(&self) -> Result<HashMap<String, Value>> {
fn collect(&self) -> Result<Map<String, Value>> {
self.cache.clone().into_table()
}
}
5 changes: 3 additions & 2 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::collections::{HashMap, VecDeque};
use std::collections::VecDeque;
use std::iter::Enumerate;

use serde::de;

use crate::config::Config;
use crate::error::*;
use crate::map::Map;
use crate::value::{Table, Value, ValueKind};

impl<'de> de::Deserializer<'de> for Value {
Expand Down Expand Up @@ -199,7 +200,7 @@ struct MapAccess {
}

impl MapAccess {
fn new(table: HashMap<String, Value>) -> Self {
fn new(table: Map<String, Value>) -> Self {
MapAccess {
elements: table.into_iter().collect(),
}
Expand Down
6 changes: 3 additions & 3 deletions src/env.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::env;

use crate::error::*;
use crate::map::Map;
use crate::source::Source;
use crate::value::{Value, ValueKind};

Expand Down Expand Up @@ -79,8 +79,8 @@ impl Source for Environment {
Box::new((*self).clone())
}

fn collect(&self) -> Result<HashMap<String, Value>> {
let mut m = HashMap::new();
fn collect(&self) -> Result<Map<String, Value>> {
let mut m = Map::new();
let uri: String = "the environment".into();

let separator = self.separator.as_deref().unwrap_or("");
Expand Down
8 changes: 4 additions & 4 deletions src/file/format/hjson.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use std::collections::HashMap;
use std::error::Error;

use crate::map::Map;
use crate::value::{Value, ValueKind};

pub fn parse(
uri: Option<&String>,
text: &str,
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
// Parse a JSON object value from the text
// TODO: Have a proper error fire if the root of a file is ever not a Table
let value = from_hjson_value(uri, &serde_hjson::from_str(text)?);
match value.kind {
ValueKind::Table(map) => Ok(map),

_ => Ok(HashMap::new()),
_ => Ok(Map::new()),
}
}

Expand All @@ -30,7 +30,7 @@ fn from_hjson_value(uri: Option<&String>, value: &serde_hjson::Value) -> Value {
serde_hjson::Value::Bool(value) => Value::new(uri, ValueKind::Boolean(value)),

serde_hjson::Value::Object(ref table) => {
let mut m = HashMap::new();
let mut m = Map::new();

for (key, value) in table {
m.insert(key.clone(), from_hjson_value(uri, value));
Expand Down
8 changes: 4 additions & 4 deletions src/file/format/ini.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use std::collections::HashMap;
use std::error::Error;

use ini::Ini;

use crate::map::Map;
use crate::value::{Value, ValueKind};

pub fn parse(
uri: Option<&String>,
text: &str,
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
let mut map: HashMap<String, Value> = HashMap::new();
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
let mut map: Map<String, Value> = Map::new();
let i = Ini::load_from_str(text)?;
for (sec, prop) in i.iter() {
match sec {
Some(sec) => {
let mut sec_map: HashMap<String, Value> = HashMap::new();
let mut sec_map: Map<String, Value> = Map::new();
for (k, v) in prop.iter() {
sec_map.insert(
k.to_owned(),
Expand Down
8 changes: 4 additions & 4 deletions src/file/format/json.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use std::collections::HashMap;
use std::error::Error;

use crate::map::Map;
use crate::value::{Value, ValueKind};

pub fn parse(
uri: Option<&String>,
text: &str,
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
// Parse a JSON object value from the text
// TODO: Have a proper error fire if the root of a file is ever not a Table
let value = from_json_value(uri, &serde_json::from_str(text)?);
match value.kind {
ValueKind::Table(map) => Ok(map),

_ => Ok(HashMap::new()),
_ => Ok(Map::new()),
}
}

Expand All @@ -34,7 +34,7 @@ fn from_json_value(uri: Option<&String>, value: &serde_json::Value) -> Value {
serde_json::Value::Bool(value) => Value::new(uri, ValueKind::Boolean(value)),

serde_json::Value::Object(ref table) => {
let mut m = HashMap::new();
let mut m = Map::new();

for (key, value) in table {
m.insert(key.clone(), from_json_value(uri, value));
Expand Down
Loading

0 comments on commit 0d3a5c3

Please sign in to comment.