Skip to content

Commit 0d3a5c3

Browse files
Merge pull request #217 from dlo9/master
Preserve map ordering
2 parents 74a0a80 + 9075ca9 commit 0d3a5c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+375
-183
lines changed

.github/workflows/msrv.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,23 @@ jobs:
6363
uses: actions-rs/cargo@v1
6464
with:
6565
command: test
66+
args: --all-features
6667

6768
- name: Run cargo test (nightly)
6869
if: matrix.rust == '1.46.0'
6970
continue-on-error: true
7071
uses: actions-rs/cargo@v1
7172
with:
7273
command: test
73-
args: --tests
74+
args: --tests --all-features
7475

7576
- name: Run cargo test (nightly)
7677
if: matrix.rust == 'nightly'
7778
continue-on-error: true
7879
uses: actions-rs/cargo@v1
7980
with:
8081
command: test
82+
args: --all-features
8183

8284
fmt:
8385
needs: [check]

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ yaml = ["yaml-rust"]
2121
hjson = ["serde-hjson"]
2222
ini = ["rust-ini"]
2323
json5 = ["json5_rs"]
24+
preserve_order = ["indexmap", "toml/preserve_order", "serde_json/preserve_order", "ron/indexmap"]
2425

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

3941
[dev-dependencies]
4042
serde_derive = "1.0.8"

examples/async_source/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::{collections::HashMap, error::Error};
1+
use std::error::Error;
22

3-
use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat};
3+
use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat, Map};
44

55
use async_trait::async_trait;
66
use futures::{select, FutureExt};
@@ -56,7 +56,7 @@ struct HttpSource {
5656

5757
#[async_trait]
5858
impl AsyncSource for HttpSource {
59-
async fn collect(&self) -> Result<HashMap<String, config::Value>, ConfigError> {
59+
async fn collect(&self) -> Result<Map<String, config::Value>, ConfigError> {
6060
reqwest::get(&self.uri)
6161
.await
6262
.map_err(|e| ConfigError::Foreign(Box::new(e)))? // error conversion is possible from custom AsyncSource impls

examples/glob/src/main.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::path::Path;
2-
use std::collections::HashMap;
2+
use std::collections::Map;
33
use config::*;
44
use glob::glob;
55

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

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

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

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

3535
// Option 3
3636
// --------
@@ -43,7 +43,7 @@ fn main() {
4343
.collect::<Vec<_>>())
4444
.unwrap();
4545

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

examples/simple/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::Map;
22

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

12-
// Print out our settings (as a HashMap)
12+
// Print out our settings (as a Map)
1313
println!("{:?}",
14-
settings.try_into::<HashMap<String, String>>().unwrap());
14+
settings.try_into::<Map<String, String>>().unwrap());
1515
}

examples/watch/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use config::*;
2-
use std::collections::HashMap;
2+
use std::collections::Map;
33
use std::sync::RwLock;
44
use notify::{RecommendedWatcher, DebouncedEvent, Watcher, RecursiveMode};
55
use std::sync::mpsc::channel;
@@ -20,7 +20,7 @@ fn show() {
2020
.read()
2121
.unwrap()
2222
.clone()
23-
.try_into::<HashMap<String, String>>()
23+
.try_into::<Map<String, String>>()
2424
.unwrap());
2525
}
2626

src/builder.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use std::iter::IntoIterator;
12
use std::str::FromStr;
2-
use std::{collections::HashMap, iter::IntoIterator};
33

44
use crate::error::Result;
5+
use crate::map::Map;
56
use crate::source::AsyncSource;
67
use crate::{config::Config, path::Expression, source::Source, value::Value};
78

@@ -87,8 +88,8 @@ use crate::{config::Config, path::Expression, source::Source, value::Value};
8788
/// ```
8889
#[derive(Debug, Clone, Default)]
8990
pub struct ConfigBuilder<St: BuilderState> {
90-
defaults: HashMap<Expression, Value>,
91-
overrides: HashMap<Expression, Value>,
91+
defaults: Map<Expression, Value>,
92+
overrides: Map<Expression, Value>,
9293
state: St,
9394
}
9495

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

@@ -244,11 +245,11 @@ impl ConfigBuilder<DefaultState> {
244245
}
245246

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

253254
// Add defaults
254255
for (key, val) in defaults.into_iter() {
@@ -322,11 +323,11 @@ impl ConfigBuilder<AsyncState> {
322323
}
323324

324325
async fn build_internal(
325-
defaults: HashMap<Expression, Value>,
326-
overrides: HashMap<Expression, Value>,
326+
defaults: Map<Expression, Value>,
327+
overrides: Map<Expression, Value>,
327328
sources: &[SourceType],
328329
) -> Result<Config> {
329-
let mut cache: Value = HashMap::<String, Value>::new().into();
330+
let mut cache: Value = Map::<String, Value>::new().into();
330331

331332
// Add defaults
332333
for (key, val) in defaults.into_iter() {

src/config.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use std::collections::HashMap;
21
use std::fmt::Debug;
32

43
use crate::builder::{ConfigBuilder, DefaultState};
54
use serde::de::Deserialize;
65
use serde::ser::Serialize;
76

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

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

8888
// Add defaults
8989
for (key, val) in self.defaults.iter() {
@@ -181,7 +181,7 @@ impl Config {
181181
self.get(key).and_then(Value::into_bool)
182182
}
183183

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

@@ -212,7 +212,7 @@ impl Source for Config {
212212
Box::new((*self).clone())
213213
}
214214

215-
fn collect(&self) -> Result<HashMap<String, Value>> {
215+
fn collect(&self) -> Result<Map<String, Value>> {
216216
self.cache.clone().into_table()
217217
}
218218
}

src/de.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use std::collections::{HashMap, VecDeque};
1+
use std::collections::VecDeque;
22
use std::iter::Enumerate;
33

44
use serde::de;
55

66
use crate::config::Config;
77
use crate::error::*;
8+
use crate::map::Map;
89
use crate::value::{Table, Value, ValueKind};
910

1011
impl<'de> de::Deserializer<'de> for Value {
@@ -199,7 +200,7 @@ struct MapAccess {
199200
}
200201

201202
impl MapAccess {
202-
fn new(table: HashMap<String, Value>) -> Self {
203+
fn new(table: Map<String, Value>) -> Self {
203204
MapAccess {
204205
elements: table.into_iter().collect(),
205206
}

src/env.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::collections::HashMap;
21
use std::env;
32

43
use crate::error::*;
4+
use crate::map::Map;
55
use crate::source::Source;
66
use crate::value::{Value, ValueKind};
77

@@ -79,8 +79,8 @@ impl Source for Environment {
7979
Box::new((*self).clone())
8080
}
8181

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

8686
let separator = self.separator.as_deref().unwrap_or("");

src/file/format/hjson.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
use std::collections::HashMap;
21
use std::error::Error;
32

3+
use crate::map::Map;
44
use crate::value::{Value, ValueKind};
55

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

16-
_ => Ok(HashMap::new()),
16+
_ => Ok(Map::new()),
1717
}
1818
}
1919

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

3232
serde_hjson::Value::Object(ref table) => {
33-
let mut m = HashMap::new();
33+
let mut m = Map::new();
3434

3535
for (key, value) in table {
3636
m.insert(key.clone(), from_hjson_value(uri, value));

src/file/format/ini.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
use std::collections::HashMap;
21
use std::error::Error;
32

43
use ini::Ini;
54

5+
use crate::map::Map;
66
use crate::value::{Value, ValueKind};
77

88
pub fn parse(
99
uri: Option<&String>,
1010
text: &str,
11-
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
12-
let mut map: HashMap<String, Value> = HashMap::new();
11+
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
12+
let mut map: Map<String, Value> = Map::new();
1313
let i = Ini::load_from_str(text)?;
1414
for (sec, prop) in i.iter() {
1515
match sec {
1616
Some(sec) => {
17-
let mut sec_map: HashMap<String, Value> = HashMap::new();
17+
let mut sec_map: Map<String, Value> = Map::new();
1818
for (k, v) in prop.iter() {
1919
sec_map.insert(
2020
k.to_owned(),

src/file/format/json.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
use std::collections::HashMap;
21
use std::error::Error;
32

3+
use crate::map::Map;
44
use crate::value::{Value, ValueKind};
55

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

16-
_ => Ok(HashMap::new()),
16+
_ => Ok(Map::new()),
1717
}
1818
}
1919

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

3636
serde_json::Value::Object(ref table) => {
37-
let mut m = HashMap::new();
37+
let mut m = Map::new();
3838

3939
for (key, value) in table {
4040
m.insert(key.clone(), from_json_value(uri, value));

0 commit comments

Comments
 (0)