From 62c84297e5340d717d89c5c0b36ed86dd5ad9d2f Mon Sep 17 00:00:00 2001 From: David Orchard Date: Wed, 28 Jul 2021 22:49:48 -0700 Subject: [PATCH 01/10] Create test cases to demonstrate lossy map order --- tests/Settings.hjson | 2 ++ tests/Settings.json | 4 +++- tests/Settings.json5 | 2 ++ tests/Settings.ron | 4 +++- tests/Settings.toml | 2 ++ tests/Settings.yaml | 2 ++ tests/file_hjson.rs | 11 +++++++++-- tests/file_json.rs | 11 +++++++++-- tests/file_json5.rs | 11 +++++++++-- tests/file_ron.rs | 11 +++++++++-- tests/file_toml.rs | 11 +++++++++-- tests/file_yaml.rs | 11 +++++++++-- tests/get.rs | 10 ++++++++-- tests/legacy/file_hjson.rs | 11 +++++++++-- tests/legacy/file_json.rs | 11 +++++++++-- tests/legacy/file_ron.rs | 11 +++++++++-- tests/legacy/file_toml.rs | 11 +++++++++-- tests/legacy/file_yaml.rs | 11 +++++++++-- tests/legacy/get.rs | 10 ++++++++-- tests/legacy/merge.rs | 14 +++++++++++--- tests/merge.rs | 14 +++++++++++--- 21 files changed, 151 insertions(+), 34 deletions(-) diff --git a/tests/Settings.hjson b/tests/Settings.hjson index 3e04ccfb..9810e04d 100644 --- a/tests/Settings.hjson +++ b/tests/Settings.hjson @@ -11,6 +11,8 @@ rating: 4.5 creator: { name: John Smith + username: jsmith + email: jsmith@localhost } } } diff --git a/tests/Settings.json b/tests/Settings.json index 001948dd..babb0ba9 100644 --- a/tests/Settings.json +++ b/tests/Settings.json @@ -11,7 +11,9 @@ "reviews": 3866, "rating": 4.5, "creator": { - "name": "John Smith" + "name": "John Smith", + "username": "jsmith", + "email": "jsmith@localhost" } } } diff --git a/tests/Settings.json5 b/tests/Settings.json5 index cfab1f53..4c93e421 100644 --- a/tests/Settings.json5 +++ b/tests/Settings.json5 @@ -13,6 +13,8 @@ rating: 4.5, creator: { name: "John Smith", + "username": "jsmith", + "email": "jsmith@localhost", } } } diff --git a/tests/Settings.ron b/tests/Settings.ron index 528fd615..7882840a 100644 --- a/tests/Settings.ron +++ b/tests/Settings.ron @@ -12,7 +12,9 @@ rating: Some(4.5), telephone: None, creator: { - "name": "John Smith" + "name": "John Smith", + "username": "jsmith", + "email": "jsmith@localhost" } ) ) diff --git a/tests/Settings.toml b/tests/Settings.toml index bafb3199..bb538087 100644 --- a/tests/Settings.toml +++ b/tests/Settings.toml @@ -41,6 +41,8 @@ rating = 4.5 [place.creator] name = "John Smith" +username = "jsmith" +email = "jsmith@localhost" [proton] up = 2 diff --git a/tests/Settings.yaml b/tests/Settings.yaml index c92fcb03..8e79c29d 100644 --- a/tests/Settings.yaml +++ b/tests/Settings.yaml @@ -10,3 +10,5 @@ place: rating: 4.5 creator: name: John Smith + username: jsmith + email: jsmith@localhost diff --git a/tests/file_hjson.rs b/tests/file_hjson.rs index 4002a903..96fe8b14 100644 --- a/tests/file_hjson.rs +++ b/tests/file_hjson.rs @@ -60,8 +60,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/file_json.rs b/tests/file_json.rs index 4563e42d..4e5edbcc 100644 --- a/tests/file_json.rs +++ b/tests/file_json.rs @@ -60,8 +60,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/file_json5.rs b/tests/file_json5.rs index d22b7265..0bf51380 100644 --- a/tests/file_json5.rs +++ b/tests/file_json5.rs @@ -59,8 +59,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/file_ron.rs b/tests/file_ron.rs index d60c8905..c9014196 100644 --- a/tests/file_ron.rs +++ b/tests/file_ron.rs @@ -62,8 +62,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/file_toml.rs b/tests/file_toml.rs index 9493bbde..7c57c4b8 100644 --- a/tests/file_toml.rs +++ b/tests/file_toml.rs @@ -71,8 +71,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/file_yaml.rs b/tests/file_yaml.rs index 90feefcf..2ea9db4c 100644 --- a/tests/file_yaml.rs +++ b/tests/file_yaml.rs @@ -60,8 +60,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/get.rs b/tests/get.rs index c6030aea..99f9c848 100644 --- a/tests/get.rs +++ b/tests/get.rs @@ -122,8 +122,14 @@ fn test_map_str() { let c = make(); let m: HashMap = c.get("place.creator").unwrap(); - assert_eq!(m.len(), 1); - assert_eq!(m["name"], "John Smith".to_string()); + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "John Smith".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); } #[test] diff --git a/tests/legacy/file_hjson.rs b/tests/legacy/file_hjson.rs index 120bcc65..ecc5165b 100644 --- a/tests/legacy/file_hjson.rs +++ b/tests/legacy/file_hjson.rs @@ -58,8 +58,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/legacy/file_json.rs b/tests/legacy/file_json.rs index e2300c6d..0ad2c8c8 100644 --- a/tests/legacy/file_json.rs +++ b/tests/legacy/file_json.rs @@ -58,8 +58,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/legacy/file_ron.rs b/tests/legacy/file_ron.rs index 91f88f31..912f6548 100644 --- a/tests/legacy/file_ron.rs +++ b/tests/legacy/file_ron.rs @@ -60,8 +60,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/legacy/file_toml.rs b/tests/legacy/file_toml.rs index 22719629..13e35906 100644 --- a/tests/legacy/file_toml.rs +++ b/tests/legacy/file_toml.rs @@ -69,8 +69,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/legacy/file_yaml.rs b/tests/legacy/file_yaml.rs index 5d7a60f3..930a6f74 100644 --- a/tests/legacy/file_yaml.rs +++ b/tests/legacy/file_yaml.rs @@ -58,8 +58,15 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place.creator["name"].clone().into_string().unwrap(), - "John Smith".to_string() + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] ); } diff --git a/tests/legacy/get.rs b/tests/legacy/get.rs index 48a7b433..fe116570 100644 --- a/tests/legacy/get.rs +++ b/tests/legacy/get.rs @@ -120,8 +120,14 @@ fn test_map_str() { let c = make(); let m: HashMap = c.get("place.creator").unwrap(); - assert_eq!(m.len(), 1); - assert_eq!(m["name"], "John Smith".to_string()); + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "John Smith".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); } #[test] diff --git a/tests/legacy/merge.rs b/tests/legacy/merge.rs index 989ae47e..a489bdfc 100644 --- a/tests/legacy/merge.rs +++ b/tests/legacy/merge.rs @@ -2,6 +2,8 @@ extern crate config; +use std::collections::HashMap; + use self::config::*; fn make() -> Config { @@ -21,11 +23,17 @@ fn test_merge() { assert_eq!(c.get("debug").ok(), Some(false)); assert_eq!(c.get("production").ok(), Some(true)); + assert_eq!(c.get("place.rating").ok(), Some(4.9)); + + let m: HashMap = c.get("place.creator").unwrap(); assert_eq!( - c.get("place.creator.name").ok(), - Some("Somebody New".to_string()) + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "Somebody New".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] ); - assert_eq!(c.get("place.rating").ok(), Some(4.9)); } #[test] diff --git a/tests/merge.rs b/tests/merge.rs index 9de36b25..8d094178 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -2,6 +2,8 @@ extern crate config; +use std::collections::HashMap; + use config::*; fn make() -> Config { @@ -18,11 +20,17 @@ fn test_merge() { assert_eq!(c.get("debug").ok(), Some(false)); assert_eq!(c.get("production").ok(), Some(true)); + assert_eq!(c.get("place.rating").ok(), Some(4.9)); + + let m: HashMap = c.get("place.creator").unwrap(); assert_eq!( - c.get("place.creator.name").ok(), - Some("Somebody New".to_string()) + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "Somebody New".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] ); - assert_eq!(c.get("place.rating").ok(), Some(4.9)); } #[test] From fc8cf0ed674cbb495df1baff34d4b832ca5fad3c Mon Sep 17 00:00:00 2001 From: David Orchard Date: Wed, 28 Jul 2021 22:52:15 -0700 Subject: [PATCH 02/10] Use LinkedHashMap in place of HashMap --- Cargo.toml | 1 + examples/async_source/main.rs | 5 +++-- examples/glob/src/main.rs | 14 +++++++------- examples/simple/src/main.rs | 6 +++--- examples/watch/src/main.rs | 4 ++-- src/builder.rs | 23 ++++++++++++----------- src/config.rs | 12 ++++++------ src/de.rs | 5 +++-- src/env.rs | 6 +++--- src/file/format/hjson.rs | 8 ++++---- src/file/format/ini.rs | 8 ++++---- src/file/format/json.rs | 8 ++++---- src/file/format/json5.rs | 8 ++++---- src/file/format/mod.rs | 8 ++++---- src/file/format/ron.rs | 8 ++++---- src/file/format/toml.rs | 8 ++++---- src/file/format/yaml.rs | 8 ++++---- src/file/mod.rs | 6 +++--- src/path/mod.rs | 10 +++++----- src/source.rs | 22 +++++++++++----------- src/value.rs | 10 +++++----- tests/async_builder.rs | 3 ++- tests/errors.rs | 3 ++- tests/file_hjson.rs | 4 ++-- tests/file_json.rs | 4 ++-- tests/file_json5.rs | 4 ++-- tests/file_ron.rs | 4 ++-- tests/file_toml.rs | 4 ++-- tests/file_yaml.rs | 4 ++-- tests/get.rs | 15 ++++++++------- tests/legacy/errors.rs | 3 ++- tests/legacy/file_hjson.rs | 4 ++-- tests/legacy/file_json.rs | 4 ++-- tests/legacy/file_ron.rs | 4 ++-- tests/legacy/file_toml.rs | 4 ++-- tests/legacy/file_yaml.rs | 4 ++-- tests/legacy/get.rs | 15 ++++++++------- tests/legacy/merge.rs | 5 ++--- tests/merge.rs | 5 ++--- 39 files changed, 144 insertions(+), 137 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f72389ff..68e66177 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,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" } +linked-hash-map = { version = "0.5.4", features = ["serde_impl"] } [dev-dependencies] serde_derive = "1.0.8" diff --git a/examples/async_source/main.rs b/examples/async_source/main.rs index 10befe05..6c836a39 100644 --- a/examples/async_source/main.rs +++ b/examples/async_source/main.rs @@ -1,4 +1,5 @@ -use std::{collections::HashMap, error::Error}; +use linked_hash_map::LinkedHashMap; +use std::error::Error; use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat}; @@ -56,7 +57,7 @@ struct HttpSource { #[async_trait] impl AsyncSource for HttpSource { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { reqwest::get(&self.uri) .await .map_err(|e| ConfigError::Foreign(Box::new(e)))? // error conversion is possible from custom AsyncSource impls diff --git a/examples/glob/src/main.rs b/examples/glob/src/main.rs index b3183ef7..c85f86e3 100644 --- a/examples/glob/src/main.rs +++ b/examples/glob/src/main.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::collections::HashMap; +use std::collections::LinkedHashMap; use config::*; use glob::glob; @@ -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 LinkedHashMap) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 2 // -------- @@ -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 LinkedHashMap) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 3 // -------- @@ -43,7 +43,7 @@ fn main() { .collect::>()) .unwrap(); - // Print out our settings (as a HashMap) + // Print out our settings (as a LinkedHashMap) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index 1c7ddb78..698401a4 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::LinkedHashMap; fn main() { let mut settings = config::Config::default(); @@ -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 LinkedHashMap) println!("{:?}", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/watch/src/main.rs b/examples/watch/src/main.rs index a1973907..9e676ada 100644 --- a/examples/watch/src/main.rs +++ b/examples/watch/src/main.rs @@ -1,5 +1,5 @@ use config::*; -use std::collections::HashMap; +use std::collections::LinkedHashMap; use std::sync::RwLock; use notify::{RecommendedWatcher, DebouncedEvent, Watcher, RecursiveMode}; use std::sync::mpsc::channel; @@ -20,7 +20,7 @@ fn show() { .read() .unwrap() .clone() - .try_into::>() + .try_into::>() .unwrap()); } diff --git a/src/builder.rs b/src/builder.rs index bb88f445..65f49ae5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,5 +1,6 @@ +use linked_hash_map::LinkedHashMap; +use std::iter::IntoIterator; use std::str::FromStr; -use std::{collections::HashMap, iter::IntoIterator}; use crate::error::Result; use crate::source::AsyncSource; @@ -87,8 +88,8 @@ use crate::{config::Config, path::Expression, source::Source, value::Value}; /// ``` #[derive(Debug, Clone, Default)] pub struct ConfigBuilder { - defaults: HashMap, - overrides: HashMap, + defaults: LinkedHashMap, + overrides: LinkedHashMap, state: St, } @@ -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, - overrides: HashMap, + defaults: LinkedHashMap, + overrides: LinkedHashMap, sources: Vec, } @@ -244,11 +245,11 @@ impl ConfigBuilder { } fn build_internal( - defaults: HashMap, - overrides: HashMap, + defaults: LinkedHashMap, + overrides: LinkedHashMap, sources: &[Box], ) -> Result { - let mut cache: Value = HashMap::::new().into(); + let mut cache: Value = LinkedHashMap::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { @@ -322,11 +323,11 @@ impl ConfigBuilder { } async fn build_internal( - defaults: HashMap, - overrides: HashMap, + defaults: LinkedHashMap, + overrides: LinkedHashMap, sources: &[SourceType], ) -> Result { - let mut cache: Value = HashMap::::new().into(); + let mut cache: Value = LinkedHashMap::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { diff --git a/src/config.rs b/src/config.rs index b9c64b48..6302c453 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::fmt::Debug; use crate::builder::{ConfigBuilder, DefaultState}; @@ -16,8 +16,8 @@ use crate::value::{Table, Value}; /// them according to the source's priority. #[derive(Clone, Debug)] pub struct Config { - defaults: HashMap, - overrides: HashMap, + defaults: LinkedHashMap, + overrides: LinkedHashMap, sources: Vec>, /// Root of the cached configuration. @@ -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::::new().into(); + let mut cache: Value = LinkedHashMap::::new().into(); // Add defaults for (key, val) in self.defaults.iter() { @@ -181,7 +181,7 @@ impl Config { self.get(key).and_then(Value::into_bool) } - pub fn get_table(&self, key: &str) -> Result> { + pub fn get_table(&self, key: &str) -> Result> { self.get(key).and_then(Value::into_table) } @@ -212,7 +212,7 @@ impl Source for Config { Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { self.cache.clone().into_table() } } diff --git a/src/de.rs b/src/de.rs index a7a6fb49..7d668965 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,4 +1,5 @@ -use std::collections::{HashMap, VecDeque}; +use linked_hash_map::LinkedHashMap; +use std::collections::VecDeque; use std::iter::Enumerate; use serde::de; @@ -199,7 +200,7 @@ struct MapAccess { } impl MapAccess { - fn new(table: HashMap) -> Self { + fn new(table: LinkedHashMap) -> Self { MapAccess { elements: table.into_iter().collect(), } diff --git a/src/env.rs b/src/env.rs index 3d95e179..2e487018 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::env; use crate::error::*; @@ -79,8 +79,8 @@ impl Source for Environment { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut m = HashMap::new(); + fn collect(&self) -> Result> { + let mut m = LinkedHashMap::new(); let uri: String = "the environment".into(); let separator = self.separator.as_deref().unwrap_or(""); diff --git a/src/file/format/hjson.rs b/src/file/format/hjson.rs index f94b1d34..a61afef6 100644 --- a/src/file/format/hjson.rs +++ b/src/file/format/hjson.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::value::{Value, ValueKind}; @@ -6,14 +6,14 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(LinkedHashMap::new()), } } @@ -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 = LinkedHashMap::new(); for (key, value) in table { m.insert(key.clone(), from_hjson_value(uri, value)); diff --git a/src/file/format/ini.rs b/src/file/format/ini.rs index b45695af..47f3499d 100644 --- a/src/file/format/ini.rs +++ b/src/file/format/ini.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use ini::Ini; @@ -8,13 +8,13 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { - let mut map: HashMap = HashMap::new(); +) -> Result, Box> { + let mut map: LinkedHashMap = LinkedHashMap::new(); let i = Ini::load_from_str(text)?; for (sec, prop) in i.iter() { match sec { Some(sec) => { - let mut sec_map: HashMap = HashMap::new(); + let mut sec_map: LinkedHashMap = LinkedHashMap::new(); for (k, v) in prop.iter() { sec_map.insert( k.to_owned(), diff --git a/src/file/format/json.rs b/src/file/format/json.rs index 87a6e613..a6a9443b 100644 --- a/src/file/format/json.rs +++ b/src/file/format/json.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::value::{Value, ValueKind}; @@ -6,14 +6,14 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(LinkedHashMap::new()), } } @@ -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 = LinkedHashMap::new(); for (key, value) in table { m.insert(key.clone(), from_json_value(uri, value)); diff --git a/src/file/format/json5.rs b/src/file/format/json5.rs index ea3390f7..952b265b 100644 --- a/src/file/format/json5.rs +++ b/src/file/format/json5.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::error::{ConfigError, Unexpected}; @@ -13,13 +13,13 @@ pub enum Val { Float(f64), String(String), Array(Vec), - Object(HashMap), + Object(LinkedHashMap), } pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { match json5_rs::from_str::(text)? { Val::String(ref value) => Err(Unexpected::Str(value.clone())), Val::Integer(value) => Err(Unexpected::Integer(value)), @@ -29,7 +29,7 @@ pub fn parse( Val::Null => Err(Unexpected::Unit), Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind { ValueKind::Table(map) => Ok(map), - _ => Ok(HashMap::new()), + _ => Ok(LinkedHashMap::new()), }, } .map_err(|err| ConfigError::invalid_root(uri, err)) diff --git a/src/file/format/mod.rs b/src/file/format/mod.rs index 53bacf6d..55d1c7af 100644 --- a/src/file/format/mod.rs +++ b/src/file/format/mod.rs @@ -2,7 +2,7 @@ // BUG: ? For some reason this doesn't do anything if I try and function scope this #![allow(unused_mut)] -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::value::Value; @@ -62,8 +62,8 @@ pub enum FileFormat { lazy_static! { #[doc(hidden)] // #[allow(unused_mut)] ? - pub static ref ALL_EXTENSIONS: HashMap> = { - let mut formats: HashMap> = HashMap::new(); + pub static ref ALL_EXTENSIONS: LinkedHashMap> = { + let mut formats: LinkedHashMap> = LinkedHashMap::new(); #[cfg(feature = "toml")] formats.insert(FileFormat::Toml, vec!["toml"]); @@ -107,7 +107,7 @@ impl FileFormat { self, uri: Option<&String>, text: &str, - ) -> Result, Box> { + ) -> Result, Box> { match self { #[cfg(feature = "toml")] FileFormat::Toml => toml::parse(uri, text), diff --git a/src/file/format/ron.rs b/src/file/format/ron.rs index f7dbce3d..a527d6fa 100644 --- a/src/file/format/ron.rs +++ b/src/file/format/ron.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::value::{Value, ValueKind}; @@ -6,12 +6,12 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { let value = from_ron_value(uri, ron::from_str(text)?)?; match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(HashMap::new()), + _ => Ok(LinkedHashMap::new()), } } @@ -56,7 +56,7 @@ fn from_ron_value( Ok((key, value)) }) - .collect::, _>>()?; + .collect::, _>>()?; ValueKind::Table(map) } diff --git a/src/file/format/toml.rs b/src/file/format/toml.rs index c7c59727..5468d973 100644 --- a/src/file/format/toml.rs +++ b/src/file/format/toml.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::value::{Value, ValueKind}; @@ -6,14 +6,14 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a TOML value from the provided text // TODO: Have a proper error fire if the root of a file is ever not a Table let value = from_toml_value(uri, &toml::from_str(text)?); match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(HashMap::new()), + _ => Ok(LinkedHashMap::new()), } } @@ -25,7 +25,7 @@ fn from_toml_value(uri: Option<&String>, value: &toml::Value) -> Value { toml::Value::Boolean(value) => Value::new(uri, value), toml::Value::Table(ref table) => { - let mut m = HashMap::new(); + let mut m = LinkedHashMap::new(); for (key, value) in table { m.insert(key.clone(), from_toml_value(uri, value)); diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs index 2526395f..246758ac 100644 --- a/src/file/format/yaml.rs +++ b/src/file/format/yaml.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::error::Error; use std::fmt; use std::mem; @@ -10,7 +10,7 @@ use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a YAML object from file let mut docs = yaml::YamlLoader::load_from_str(text)?; let root = match docs.len() { @@ -26,7 +26,7 @@ pub fn parse( match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(HashMap::new()), + _ => Ok(LinkedHashMap::new()), } } @@ -40,7 +40,7 @@ fn from_yaml_value(uri: Option<&String>, value: &yaml::Yaml) -> Value { yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::Integer(value)), yaml::Yaml::Boolean(value) => Value::new(uri, ValueKind::Boolean(value)), yaml::Yaml::Hash(ref table) => { - let mut m = HashMap::new(); + let mut m = LinkedHashMap::new(); for (key, value) in table { if let Some(k) = key.as_str() { m.insert(k.to_owned(), from_yaml_value(uri, value)); diff --git a/src/file/mod.rs b/src/file/mod.rs index b00a2715..02fd51f4 100644 --- a/src/file/mod.rs +++ b/src/file/mod.rs @@ -1,7 +1,7 @@ mod format; pub mod source; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::{Path, PathBuf}; use crate::error::*; @@ -99,7 +99,7 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { // Coerce the file contents to a string let (uri, contents, format) = match self .source @@ -110,7 +110,7 @@ where Err(error) => { if !self.required { - return Ok(HashMap::new()); + return Ok(LinkedHashMap::new()); } return Err(error); diff --git a/src/path/mod.rs b/src/path/mod.rs index d58a6f23..04c424c1 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::str::FromStr; use crate::error::*; @@ -135,7 +135,7 @@ impl Expression { ), _ => { - *value = HashMap::::new().into(); + *value = LinkedHashMap::::new().into(); if let ValueKind::Table(ref mut map) = value.kind { Some( @@ -186,7 +186,7 @@ impl Expression { ValueKind::Table(_) => {} _ => { - *root = HashMap::::new().into(); + *root = LinkedHashMap::::new().into(); } } @@ -195,7 +195,7 @@ impl Expression { // Pull out another table let mut target = if let ValueKind::Table(ref mut map) = root.kind { map.entry(id.clone()) - .or_insert_with(|| HashMap::::new().into()) + .or_insert_with(|| LinkedHashMap::::new().into()) } else { unreachable!(); }; @@ -224,7 +224,7 @@ impl Expression { _ => { // Didn't find a table. Oh well. Make a table and do this anyway - *parent = HashMap::::new().into(); + *parent = LinkedHashMap::::new().into(); Expression::Identifier(key.clone()).set(parent, value); } diff --git a/src/source.rs b/src/source.rs index 831e4c4c..7d257d09 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::fmt::Debug; use std::str::FromStr; @@ -13,8 +13,8 @@ pub trait Source: Debug { fn clone_into_box(&self) -> Box; /// Collect all configuration properties available from this source and return - /// a HashMap. - fn collect(&self) -> Result>; + /// a LinkedHashMap. + fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -55,8 +55,8 @@ pub trait AsyncSource: Debug + Sync { // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits /// Collects all configuration properties available from this source and return - /// a HashMap as an async operations. - async fn collect(&self) -> Result>; + /// a LinkedHashMap as an async operations. + async fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. async fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -86,8 +86,8 @@ impl Source for Vec> { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = HashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = LinkedHashMap::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -106,8 +106,8 @@ impl Source for [Box] { Box::new(self.to_owned()) } - fn collect(&self) -> Result> { - let mut cache: Value = HashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = LinkedHashMap::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -131,8 +131,8 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = HashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = LinkedHashMap::::new().into(); for source in self { source.collect_to(&mut cache)?; diff --git a/src/value.rs b/src/value.rs index 8db5fcc1..e8f41c90 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::fmt; use std::fmt::Display; @@ -23,7 +23,7 @@ pub enum ValueKind { } pub type Array = Vec; -pub type Table = HashMap; +pub type Table = LinkedHashMap; impl Default for ValueKind { fn default() -> Self { @@ -73,11 +73,11 @@ impl From for ValueKind { } } -impl From> for ValueKind +impl From> for ValueKind where T: Into, { - fn from(values: HashMap) -> Self { + fn from(values: LinkedHashMap) -> Self { let t = values.into_iter().map(|(k, v)| (k, v.into())).collect(); ValueKind::Table(t) } @@ -357,7 +357,7 @@ impl Value { /// If the `Value` is a Table, returns the associated Map. // FIXME: Should this not be `try_into_*` ? - pub fn into_table(self) -> Result> { + pub fn into_table(self) -> Result> { match self.kind { ValueKind::Table(value) => Ok(value), diff --git a/tests/async_builder.rs b/tests/async_builder.rs index 5d7d6ba6..a614d424 100644 --- a/tests/async_builder.rs +++ b/tests/async_builder.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use config::*; +use linked_hash_map::LinkedHashMap; use std::{env, fs, path, str::FromStr}; use tokio::{fs::File, io::AsyncReadExt}; @@ -18,7 +19,7 @@ impl AsyncFile { #[async_trait] impl AsyncSource for AsyncFile { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { let mut path = env::current_dir().unwrap(); let local = path::PathBuf::from_str(&self.path).unwrap(); diff --git a/tests/errors.rs b/tests/errors.rs index e11ad69b..703dddd8 100644 --- a/tests/errors.rs +++ b/tests/errors.rs @@ -5,6 +5,7 @@ extern crate config; #[macro_use] extern crate serde_derive; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -96,7 +97,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/file_hjson.rs b/tests/file_hjson.rs index 96fe8b14..c6d9bd5b 100644 --- a/tests/file_hjson.rs +++ b/tests/file_hjson.rs @@ -7,7 +7,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/file_json.rs b/tests/file_json.rs index 4e5edbcc..c3ebe069 100644 --- a/tests/file_json.rs +++ b/tests/file_json.rs @@ -7,7 +7,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/file_json5.rs b/tests/file_json5.rs index 0bf51380..f92bce52 100644 --- a/tests/file_json5.rs +++ b/tests/file_json5.rs @@ -9,7 +9,7 @@ extern crate serde_derive; use config::*; use float_cmp::ApproxEqUlps; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; #[derive(Debug, Deserialize)] @@ -20,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/file_ron.rs b/tests/file_ron.rs index c9014196..71b9106e 100644 --- a/tests/file_ron.rs +++ b/tests/file_ron.rs @@ -7,7 +7,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -22,7 +22,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/file_toml.rs b/tests/file_toml.rs index 7c57c4b8..77d4d31d 100644 --- a/tests/file_toml.rs +++ b/tests/file_toml.rs @@ -7,7 +7,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -22,7 +22,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/file_yaml.rs b/tests/file_yaml.rs index 2ea9db4c..4b1c1088 100644 --- a/tests/file_yaml.rs +++ b/tests/file_yaml.rs @@ -7,7 +7,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/get.rs b/tests/get.rs index 99f9c848..43a126a8 100644 --- a/tests/get.rs +++ b/tests/get.rs @@ -7,7 +7,8 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use std::collections::{HashMap, HashSet}; +use linked_hash_map::LinkedHashMap; +use std::collections::HashSet; use config::*; use float_cmp::ApproxEqUlps; @@ -107,7 +108,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: HashMap = c.get("place").unwrap(); + let m: LinkedHashMap = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -120,7 +121,7 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: HashMap = c.get("place.creator").unwrap(); + let m: LinkedHashMap = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), @@ -136,7 +137,7 @@ fn test_map_str() { fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: HashMap, + place: LinkedHashMap, } let c = make(); @@ -221,7 +222,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: HashMap, + diodes: LinkedHashMap, } let c = make(); @@ -254,7 +255,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: HashMap, + proton: LinkedHashMap, // Just to make sure that set keys work too. quarks: HashSet, } @@ -270,7 +271,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: HashMap, + divisors: LinkedHashMap, } let c = make(); diff --git a/tests/legacy/errors.rs b/tests/legacy/errors.rs index 9058c805..070eb6d8 100644 --- a/tests/legacy/errors.rs +++ b/tests/legacy/errors.rs @@ -2,6 +2,7 @@ extern crate config; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -93,7 +94,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/legacy/file_hjson.rs b/tests/legacy/file_hjson.rs index ecc5165b..2f5717fa 100644 --- a/tests/legacy/file_hjson.rs +++ b/tests/legacy/file_hjson.rs @@ -4,7 +4,7 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/legacy/file_json.rs b/tests/legacy/file_json.rs index 0ad2c8c8..6a9b5770 100644 --- a/tests/legacy/file_json.rs +++ b/tests/legacy/file_json.rs @@ -4,7 +4,7 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/legacy/file_ron.rs b/tests/legacy/file_ron.rs index 912f6548..bfd31af7 100644 --- a/tests/legacy/file_ron.rs +++ b/tests/legacy/file_ron.rs @@ -4,7 +4,7 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -19,7 +19,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/legacy/file_toml.rs b/tests/legacy/file_toml.rs index 13e35906..24c590eb 100644 --- a/tests/legacy/file_toml.rs +++ b/tests/legacy/file_toml.rs @@ -4,7 +4,7 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -19,7 +19,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/legacy/file_yaml.rs b/tests/legacy/file_yaml.rs index 930a6f74..af04ef62 100644 --- a/tests/legacy/file_yaml.rs +++ b/tests/legacy/file_yaml.rs @@ -4,7 +4,7 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::HashMap; +use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: HashMap, + creator: LinkedHashMap, rating: Option, } diff --git a/tests/legacy/get.rs b/tests/legacy/get.rs index fe116570..c2465676 100644 --- a/tests/legacy/get.rs +++ b/tests/legacy/get.rs @@ -4,7 +4,8 @@ extern crate config; extern crate float_cmp; extern crate serde; -use std::collections::{HashMap, HashSet}; +use linked_hash_map::LinkedHashMap; +use std::collections::HashSet; use self::config::*; use self::float_cmp::ApproxEqUlps; @@ -105,7 +106,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: HashMap = c.get("place").unwrap(); + let m: LinkedHashMap = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -118,7 +119,7 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: HashMap = c.get("place.creator").unwrap(); + let m: LinkedHashMap = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), @@ -134,7 +135,7 @@ fn test_map_str() { fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: HashMap, + place: LinkedHashMap, } let c = make(); @@ -219,7 +220,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: HashMap, + diodes: LinkedHashMap, } let c = make(); @@ -252,7 +253,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: HashMap, + proton: LinkedHashMap, // Just to make sure that set keys work too. quarks: HashSet, } @@ -268,7 +269,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: HashMap, + divisors: LinkedHashMap, } let c = make(); diff --git a/tests/legacy/merge.rs b/tests/legacy/merge.rs index a489bdfc..75cb16d5 100644 --- a/tests/legacy/merge.rs +++ b/tests/legacy/merge.rs @@ -2,9 +2,8 @@ extern crate config; -use std::collections::HashMap; - use self::config::*; +use linked_hash_map::LinkedHashMap; fn make() -> Config { let mut c = Config::default(); @@ -25,7 +24,7 @@ fn test_merge() { assert_eq!(c.get("production").ok(), Some(true)); assert_eq!(c.get("place.rating").ok(), Some(4.9)); - let m: HashMap = c.get("place.creator").unwrap(); + let m: LinkedHashMap = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), vec![ diff --git a/tests/merge.rs b/tests/merge.rs index 8d094178..922ae317 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -2,9 +2,8 @@ extern crate config; -use std::collections::HashMap; - use config::*; +use linked_hash_map::LinkedHashMap; fn make() -> Config { Config::builder() @@ -22,7 +21,7 @@ fn test_merge() { assert_eq!(c.get("production").ok(), Some(true)); assert_eq!(c.get("place.rating").ok(), Some(4.9)); - let m: HashMap = c.get("place.creator").unwrap(); + let m: LinkedHashMap = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), vec![ From f14adeb0984f81883cd85c6590c960f4dcadb59b Mon Sep 17 00:00:00 2001 From: David Orchard Date: Wed, 28 Jul 2021 23:49:31 -0700 Subject: [PATCH 03/10] Enable dependency features for map order preservation --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68e66177..3c2e6227 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,12 +28,12 @@ lazy_static = "1.0" serde = "1.0.8" nom = "6" -toml = { version = "0.5", optional = true } -serde_json = { version = "1.0.2", optional = true } +toml = { version = "0.5", features = ["preserve_order"], optional = true } +serde_json = { version = "1.0.2", features = ["std", "preserve_order"], optional = true } yaml-rust = { version = "0.4", optional = true } serde-hjson = { version = "0.9", default-features = false, optional = true } rust-ini = { version = "0.17", optional = true } -ron = { version = "0.6", optional = true } +ron = { version = "0.6", features = ["indexmap"], optional = true } json5_rs = { version = "0.3", optional = true, package = "json5" } linked-hash-map = { version = "0.5.4", features = ["serde_impl"] } From 7134592270190c28e538d580a3d55b0f1ff753f8 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Wed, 28 Jul 2021 23:51:02 -0700 Subject: [PATCH 04/10] Preserve map order when merging --- src/path/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/path/mod.rs b/src/path/mod.rs index 04c424c1..b0564676 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -209,7 +209,11 @@ impl Expression { _ => { if let ValueKind::Table(ref mut map) = root.kind { // Just do a simple set - map.insert(id.clone(), value); + if let Some(existing) = map.get_mut(id) { + *existing = value; + } else { + map.insert(id.clone(), value); + } } } } From 622efaca17256fb42dafc61c8df1f3037c1fb772 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Thu, 29 Jul 2021 00:02:39 -0700 Subject: [PATCH 05/10] Disable map order preservation for hjson --- tests/file_hjson.rs | 11 ++--------- tests/legacy/file_hjson.rs | 11 ++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/file_hjson.rs b/tests/file_hjson.rs index c6d9bd5b..376993f1 100644 --- a/tests/file_hjson.rs +++ b/tests/file_hjson.rs @@ -60,15 +60,8 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() ); } diff --git a/tests/legacy/file_hjson.rs b/tests/legacy/file_hjson.rs index 2f5717fa..b846c919 100644 --- a/tests/legacy/file_hjson.rs +++ b/tests/legacy/file_hjson.rs @@ -58,15 +58,8 @@ fn test_file() { assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() ); } From cc0530a7716779f954b1756905a9f4ceb7eb6d62 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Sun, 1 Aug 2021 00:03:10 -0700 Subject: [PATCH 06/10] Move order preservation under a feature gate --- Cargo.toml | 12 ++++++++---- examples/async_source/main.rs | 5 ++--- examples/glob/src/main.rs | 14 +++++++------- examples/simple/src/main.rs | 6 +++--- examples/watch/src/main.rs | 4 ++-- src/builder.rs | 23 +++++++++++----------- src/config.rs | 12 ++++++------ src/de.rs | 4 ++-- src/env.rs | 6 +++--- src/file/format/hjson.rs | 8 ++++---- src/file/format/ini.rs | 8 ++++---- src/file/format/json.rs | 8 ++++---- src/file/format/json5.rs | 8 ++++---- src/file/format/mod.rs | 8 ++++---- src/file/format/ron.rs | 8 ++++---- src/file/format/toml.rs | 8 ++++---- src/file/format/yaml.rs | 8 ++++---- src/file/mod.rs | 6 +++--- src/lib.rs | 2 ++ src/map.rs | 4 ++++ src/path/mod.rs | 10 +++++----- src/source.rs | 22 ++++++++++----------- src/value.rs | 10 +++++----- tests/async_builder.rs | 5 +++-- tests/errors.rs | 5 ++--- tests/file_hjson.rs | 3 +-- tests/file_json.rs | 32 ++++++++++++++++++------------- tests/file_json5.rs | 32 ++++++++++++++++++------------- tests/file_ron.rs | 32 ++++++++++++++++++------------- tests/file_toml.rs | 32 ++++++++++++++++++------------- tests/file_yaml.rs | 32 ++++++++++++++++++------------- tests/get.rs | 36 +++++++++++++++++++---------------- tests/legacy/errors.rs | 3 +-- tests/legacy/file_hjson.rs | 3 +-- tests/legacy/file_json.rs | 32 ++++++++++++++++++------------- tests/legacy/file_ron.rs | 32 ++++++++++++++++++------------- tests/legacy/file_toml.rs | 32 ++++++++++++++++++------------- tests/legacy/file_yaml.rs | 32 ++++++++++++++++++------------- tests/legacy/get.rs | 36 +++++++++++++++++++---------------- tests/legacy/merge.rs | 26 +++++++++++++++---------- tests/merge.rs | 26 +++++++++++++++---------- 41 files changed, 358 insertions(+), 277 deletions(-) create mode 100644 src/map.rs diff --git a/Cargo.toml b/Cargo.toml index 3c2e6227..8d76ba08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ yaml = ["yaml-rust"] hjson = ["serde-hjson"] ini = ["rust-ini"] json5 = ["json5_rs"] +preserve_order = ["linked-hash-map", "toml/preserve_order", "serde_json/preserve_order", "ron/indexmap"] [dependencies] async-trait = "0.1.50" @@ -28,14 +29,14 @@ lazy_static = "1.0" serde = "1.0.8" nom = "6" -toml = { version = "0.5", features = ["preserve_order"], optional = true } -serde_json = { version = "1.0.2", features = ["std", "preserve_order"], optional = true } +toml = { version = "0.5", optional = true } +serde_json = { version = "1.0.2", optional = true } yaml-rust = { version = "0.4", optional = true } serde-hjson = { version = "0.9", default-features = false, optional = true } rust-ini = { version = "0.17", optional = true } -ron = { version = "0.6", features = ["indexmap"], optional = true } +ron = { version = "0.6", optional = true } json5_rs = { version = "0.3", optional = true, package = "json5" } -linked-hash-map = { version = "0.5.4", features = ["serde_impl"] } +linked-hash-map = { version = "0.5.4", optional = true, features = ["serde_impl"] } [dev-dependencies] serde_derive = "1.0.8" @@ -45,3 +46,6 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util warp = "0.3.1" futures = "0.3.15" reqwest = "0.11.3" +# Workaround to activate non-default features for tests: +# https://github.com/rust-lang/cargo/issues/2911 +config = { path = ".", features = ["preserve_order"] } diff --git a/examples/async_source/main.rs b/examples/async_source/main.rs index 6c836a39..51348224 100644 --- a/examples/async_source/main.rs +++ b/examples/async_source/main.rs @@ -1,7 +1,6 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; -use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat}; +use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat, MapImpl}; use async_trait::async_trait; use futures::{select, FutureExt}; @@ -57,7 +56,7 @@ struct HttpSource { #[async_trait] impl AsyncSource for HttpSource { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { reqwest::get(&self.uri) .await .map_err(|e| ConfigError::Foreign(Box::new(e)))? // error conversion is possible from custom AsyncSource impls diff --git a/examples/glob/src/main.rs b/examples/glob/src/main.rs index c85f86e3..d429917d 100644 --- a/examples/glob/src/main.rs +++ b/examples/glob/src/main.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::collections::LinkedHashMap; +use std::collections::MapImpl; use config::*; use glob::glob; @@ -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 LinkedHashMap) + // Print out our settings (as a MapImpl) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 2 // -------- @@ -28,9 +28,9 @@ fn main() { File::from(Path::new("conf/99-extra.json"))]) .unwrap(); - // Print out our settings (as a LinkedHashMap) + // Print out our settings (as a MapImpl) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 3 // -------- @@ -43,7 +43,7 @@ fn main() { .collect::>()) .unwrap(); - // Print out our settings (as a LinkedHashMap) + // Print out our settings (as a MapImpl) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index 698401a4..5d4c3bc6 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -1,4 +1,4 @@ -use std::collections::LinkedHashMap; +use std::collections::MapImpl; fn main() { let mut settings = config::Config::default(); @@ -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 LinkedHashMap) + // Print out our settings (as a MapImpl) println!("{:?}", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/watch/src/main.rs b/examples/watch/src/main.rs index 9e676ada..fed4ed04 100644 --- a/examples/watch/src/main.rs +++ b/examples/watch/src/main.rs @@ -1,5 +1,5 @@ use config::*; -use std::collections::LinkedHashMap; +use std::collections::MapImpl; use std::sync::RwLock; use notify::{RecommendedWatcher, DebouncedEvent, Watcher, RecursiveMode}; use std::sync::mpsc::channel; @@ -20,7 +20,7 @@ fn show() { .read() .unwrap() .clone() - .try_into::>() + .try_into::>() .unwrap()); } diff --git a/src/builder.rs b/src/builder.rs index 65f49ae5..5100f5f5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,8 +1,9 @@ -use linked_hash_map::LinkedHashMap; use std::iter::IntoIterator; use std::str::FromStr; + use crate::error::Result; +use crate::map::MapImpl; use crate::source::AsyncSource; use crate::{config::Config, path::Expression, source::Source, value::Value}; @@ -88,8 +89,8 @@ use crate::{config::Config, path::Expression, source::Source, value::Value}; /// ``` #[derive(Debug, Clone, Default)] pub struct ConfigBuilder { - defaults: LinkedHashMap, - overrides: LinkedHashMap, + defaults: MapImpl, + overrides: MapImpl, state: St, } @@ -121,8 +122,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: LinkedHashMap, - overrides: LinkedHashMap, + defaults: MapImpl, + overrides: MapImpl, sources: Vec, } @@ -245,11 +246,11 @@ impl ConfigBuilder { } fn build_internal( - defaults: LinkedHashMap, - overrides: LinkedHashMap, + defaults: MapImpl, + overrides: MapImpl, sources: &[Box], ) -> Result { - let mut cache: Value = LinkedHashMap::::new().into(); + let mut cache: Value = MapImpl::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { @@ -323,11 +324,11 @@ impl ConfigBuilder { } async fn build_internal( - defaults: LinkedHashMap, - overrides: LinkedHashMap, + defaults: MapImpl, + overrides: MapImpl, sources: &[SourceType], ) -> Result { - let mut cache: Value = LinkedHashMap::::new().into(); + let mut cache: Value = MapImpl::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { diff --git a/src/config.rs b/src/config.rs index 6302c453..8c410f08 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,3 @@ -use linked_hash_map::LinkedHashMap; use std::fmt::Debug; use crate::builder::{ConfigBuilder, DefaultState}; @@ -6,6 +5,7 @@ use serde::de::Deserialize; use serde::ser::Serialize; use crate::error::*; +use crate::map::MapImpl; use crate::path; use crate::ser::ConfigSerializer; use crate::source::Source; @@ -16,8 +16,8 @@ use crate::value::{Table, Value}; /// them according to the source's priority. #[derive(Clone, Debug)] pub struct Config { - defaults: LinkedHashMap, - overrides: LinkedHashMap, + defaults: MapImpl, + overrides: MapImpl, sources: Vec>, /// Root of the cached configuration. @@ -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 = LinkedHashMap::::new().into(); + let mut cache: Value = MapImpl::::new().into(); // Add defaults for (key, val) in self.defaults.iter() { @@ -181,7 +181,7 @@ impl Config { self.get(key).and_then(Value::into_bool) } - pub fn get_table(&self, key: &str) -> Result> { + pub fn get_table(&self, key: &str) -> Result> { self.get(key).and_then(Value::into_table) } @@ -212,7 +212,7 @@ impl Source for Config { Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { self.cache.clone().into_table() } } diff --git a/src/de.rs b/src/de.rs index 7d668965..9aa6b45b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,4 +1,3 @@ -use linked_hash_map::LinkedHashMap; use std::collections::VecDeque; use std::iter::Enumerate; @@ -6,6 +5,7 @@ use serde::de; use crate::config::Config; use crate::error::*; +use crate::map::MapImpl; use crate::value::{Table, Value, ValueKind}; impl<'de> de::Deserializer<'de> for Value { @@ -200,7 +200,7 @@ struct MapAccess { } impl MapAccess { - fn new(table: LinkedHashMap) -> Self { + fn new(table: MapImpl) -> Self { MapAccess { elements: table.into_iter().collect(), } diff --git a/src/env.rs b/src/env.rs index 2e487018..507ace64 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,7 +1,7 @@ -use linked_hash_map::LinkedHashMap; use std::env; use crate::error::*; +use crate::map::MapImpl; use crate::source::Source; use crate::value::{Value, ValueKind}; @@ -79,8 +79,8 @@ impl Source for Environment { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut m = LinkedHashMap::new(); + fn collect(&self) -> Result> { + let mut m = MapImpl::new(); let uri: String = "the environment".into(); let separator = self.separator.as_deref().unwrap_or(""); diff --git a/src/file/format/hjson.rs b/src/file/format/hjson.rs index a61afef6..68b9c9c9 100644 --- a/src/file/format/hjson.rs +++ b/src/file/format/hjson.rs @@ -1,19 +1,19 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), } } @@ -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 = LinkedHashMap::new(); + let mut m = MapImpl::new(); for (key, value) in table { m.insert(key.clone(), from_hjson_value(uri, value)); diff --git a/src/file/format/ini.rs b/src/file/format/ini.rs index 47f3499d..b5f742d5 100644 --- a/src/file/format/ini.rs +++ b/src/file/format/ini.rs @@ -1,20 +1,20 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; use ini::Ini; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { - let mut map: LinkedHashMap = LinkedHashMap::new(); +) -> Result, Box> { + let mut map: MapImpl = MapImpl::new(); let i = Ini::load_from_str(text)?; for (sec, prop) in i.iter() { match sec { Some(sec) => { - let mut sec_map: LinkedHashMap = LinkedHashMap::new(); + let mut sec_map: MapImpl = MapImpl::new(); for (k, v) in prop.iter() { sec_map.insert( k.to_owned(), diff --git a/src/file/format/json.rs b/src/file/format/json.rs index a6a9443b..c4895fb6 100644 --- a/src/file/format/json.rs +++ b/src/file/format/json.rs @@ -1,19 +1,19 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), } } @@ -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 = LinkedHashMap::new(); + let mut m = MapImpl::new(); for (key, value) in table { m.insert(key.clone(), from_json_value(uri, value)); diff --git a/src/file/format/json5.rs b/src/file/format/json5.rs index 952b265b..69432c01 100644 --- a/src/file/format/json5.rs +++ b/src/file/format/json5.rs @@ -1,7 +1,7 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; use crate::error::{ConfigError, Unexpected}; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; #[derive(serde::Deserialize, Debug)] @@ -13,13 +13,13 @@ pub enum Val { Float(f64), String(String), Array(Vec), - Object(LinkedHashMap), + Object(MapImpl), } pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { match json5_rs::from_str::(text)? { Val::String(ref value) => Err(Unexpected::Str(value.clone())), Val::Integer(value) => Err(Unexpected::Integer(value)), @@ -29,7 +29,7 @@ pub fn parse( Val::Null => Err(Unexpected::Unit), Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind { ValueKind::Table(map) => Ok(map), - _ => Ok(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), }, } .map_err(|err| ConfigError::invalid_root(uri, err)) diff --git a/src/file/format/mod.rs b/src/file/format/mod.rs index 55d1c7af..df59ca61 100644 --- a/src/file/format/mod.rs +++ b/src/file/format/mod.rs @@ -2,9 +2,9 @@ // BUG: ? For some reason this doesn't do anything if I try and function scope this #![allow(unused_mut)] -use linked_hash_map::LinkedHashMap; use std::error::Error; +use crate::map::MapImpl; use crate::value::Value; #[cfg(feature = "toml")] @@ -62,8 +62,8 @@ pub enum FileFormat { lazy_static! { #[doc(hidden)] // #[allow(unused_mut)] ? - pub static ref ALL_EXTENSIONS: LinkedHashMap> = { - let mut formats: LinkedHashMap> = LinkedHashMap::new(); + pub static ref ALL_EXTENSIONS: MapImpl> = { + let mut formats: MapImpl> = MapImpl::new(); #[cfg(feature = "toml")] formats.insert(FileFormat::Toml, vec!["toml"]); @@ -107,7 +107,7 @@ impl FileFormat { self, uri: Option<&String>, text: &str, - ) -> Result, Box> { + ) -> Result, Box> { match self { #[cfg(feature = "toml")] FileFormat::Toml => toml::parse(uri, text), diff --git a/src/file/format/ron.rs b/src/file/format/ron.rs index a527d6fa..769fd538 100644 --- a/src/file/format/ron.rs +++ b/src/file/format/ron.rs @@ -1,17 +1,17 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { let value = from_ron_value(uri, ron::from_str(text)?)?; match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), } } @@ -56,7 +56,7 @@ fn from_ron_value( Ok((key, value)) }) - .collect::, _>>()?; + .collect::, _>>()?; ValueKind::Table(map) } diff --git a/src/file/format/toml.rs b/src/file/format/toml.rs index 5468d973..a4e16b2b 100644 --- a/src/file/format/toml.rs +++ b/src/file/format/toml.rs @@ -1,19 +1,19 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a TOML value from the provided text // TODO: Have a proper error fire if the root of a file is ever not a Table let value = from_toml_value(uri, &toml::from_str(text)?); match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), } } @@ -25,7 +25,7 @@ fn from_toml_value(uri: Option<&String>, value: &toml::Value) -> Value { toml::Value::Boolean(value) => Value::new(uri, value), toml::Value::Table(ref table) => { - let mut m = LinkedHashMap::new(); + let mut m = MapImpl::new(); for (key, value) in table { m.insert(key.clone(), from_toml_value(uri, value)); diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs index 246758ac..f725b1f1 100644 --- a/src/file/format/yaml.rs +++ b/src/file/format/yaml.rs @@ -1,16 +1,16 @@ -use linked_hash_map::LinkedHashMap; use std::error::Error; use std::fmt; use std::mem; use yaml_rust as yaml; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a YAML object from file let mut docs = yaml::YamlLoader::load_from_str(text)?; let root = match docs.len() { @@ -26,7 +26,7 @@ pub fn parse( match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(LinkedHashMap::new()), + _ => Ok(MapImpl::new()), } } @@ -40,7 +40,7 @@ fn from_yaml_value(uri: Option<&String>, value: &yaml::Yaml) -> Value { yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::Integer(value)), yaml::Yaml::Boolean(value) => Value::new(uri, ValueKind::Boolean(value)), yaml::Yaml::Hash(ref table) => { - let mut m = LinkedHashMap::new(); + let mut m = MapImpl::new(); for (key, value) in table { if let Some(k) = key.as_str() { m.insert(k.to_owned(), from_yaml_value(uri, value)); diff --git a/src/file/mod.rs b/src/file/mod.rs index 02fd51f4..d5744f48 100644 --- a/src/file/mod.rs +++ b/src/file/mod.rs @@ -1,10 +1,10 @@ mod format; pub mod source; -use linked_hash_map::LinkedHashMap; use std::path::{Path, PathBuf}; use crate::error::*; +use crate::map::MapImpl; use crate::source::Source; use crate::value::Value; @@ -99,7 +99,7 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { // Coerce the file contents to a string let (uri, contents, format) = match self .source @@ -110,7 +110,7 @@ where Err(error) => { if !self.required { - return Ok(LinkedHashMap::new()); + return Ok(MapImpl::new()); } return Err(error); diff --git a/src/lib.rs b/src/lib.rs index 87c82bc4..511ddd87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,7 @@ mod de; mod env; mod error; mod file; +mod map; mod path; mod ser; mod source; @@ -70,6 +71,7 @@ pub use crate::config::Config; pub use crate::env::Environment; pub use crate::error::ConfigError; pub use crate::file::{File, FileFormat, FileSourceFile, FileSourceString}; +pub use crate::map::MapImpl; pub use crate::source::AsyncSource; pub use crate::source::Source; pub use crate::value::Value; diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 00000000..ae41155e --- /dev/null +++ b/src/map.rs @@ -0,0 +1,4 @@ +#[cfg(not(feature = "preserve_order"))] +pub type MapImpl = std::collections::HashMap; +#[cfg(feature = "preserve_order")] +pub type MapImpl = linked_hash_map::LinkedHashMap; diff --git a/src/path/mod.rs b/src/path/mod.rs index b0564676..8ce51f96 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -1,7 +1,7 @@ -use linked_hash_map::LinkedHashMap; use std::str::FromStr; use crate::error::*; +use crate::map::MapImpl; use crate::value::{Value, ValueKind}; mod parser; @@ -135,7 +135,7 @@ impl Expression { ), _ => { - *value = LinkedHashMap::::new().into(); + *value = MapImpl::::new().into(); if let ValueKind::Table(ref mut map) = value.kind { Some( @@ -186,7 +186,7 @@ impl Expression { ValueKind::Table(_) => {} _ => { - *root = LinkedHashMap::::new().into(); + *root = MapImpl::::new().into(); } } @@ -195,7 +195,7 @@ impl Expression { // Pull out another table let mut target = if let ValueKind::Table(ref mut map) = root.kind { map.entry(id.clone()) - .or_insert_with(|| LinkedHashMap::::new().into()) + .or_insert_with(|| MapImpl::::new().into()) } else { unreachable!(); }; @@ -228,7 +228,7 @@ impl Expression { _ => { // Didn't find a table. Oh well. Make a table and do this anyway - *parent = LinkedHashMap::::new().into(); + *parent = MapImpl::::new().into(); Expression::Identifier(key.clone()).set(parent, value); } diff --git a/src/source.rs b/src/source.rs index 7d257d09..2c763668 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,10 +1,10 @@ -use linked_hash_map::LinkedHashMap; use std::fmt::Debug; use std::str::FromStr; use async_trait::async_trait; use crate::error::*; +use crate::map::MapImpl; use crate::path; use crate::value::{Value, ValueKind}; @@ -13,8 +13,8 @@ pub trait Source: Debug { fn clone_into_box(&self) -> Box; /// Collect all configuration properties available from this source and return - /// a LinkedHashMap. - fn collect(&self) -> Result>; + /// a MapImpl. + fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -55,8 +55,8 @@ pub trait AsyncSource: Debug + Sync { // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits /// Collects all configuration properties available from this source and return - /// a LinkedHashMap as an async operations. - async fn collect(&self) -> Result>; + /// a MapImpl as an async operations. + async fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. async fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -86,8 +86,8 @@ impl Source for Vec> { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = LinkedHashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = MapImpl::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -106,8 +106,8 @@ impl Source for [Box] { Box::new(self.to_owned()) } - fn collect(&self) -> Result> { - let mut cache: Value = LinkedHashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = MapImpl::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -131,8 +131,8 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = LinkedHashMap::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = MapImpl::::new().into(); for source in self { source.collect_to(&mut cache)?; diff --git a/src/value.rs b/src/value.rs index e8f41c90..17be54d9 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,10 +1,10 @@ -use linked_hash_map::LinkedHashMap; use std::fmt; use std::fmt::Display; use serde::de::{Deserialize, Deserializer, Visitor}; use crate::error::*; +use crate::map::MapImpl; /// Underlying kind of the configuration value. /// @@ -23,7 +23,7 @@ pub enum ValueKind { } pub type Array = Vec; -pub type Table = LinkedHashMap; +pub type Table = MapImpl; impl Default for ValueKind { fn default() -> Self { @@ -73,11 +73,11 @@ impl From for ValueKind { } } -impl From> for ValueKind +impl From> for ValueKind where T: Into, { - fn from(values: LinkedHashMap) -> Self { + fn from(values: MapImpl) -> Self { let t = values.into_iter().map(|(k, v)| (k, v.into())).collect(); ValueKind::Table(t) } @@ -357,7 +357,7 @@ impl Value { /// If the `Value` is a Table, returns the associated Map. // FIXME: Should this not be `try_into_*` ? - pub fn into_table(self) -> Result> { + pub fn into_table(self) -> Result> { match self.kind { ValueKind::Table(value) => Ok(value), diff --git a/tests/async_builder.rs b/tests/async_builder.rs index a614d424..bf923d61 100644 --- a/tests/async_builder.rs +++ b/tests/async_builder.rs @@ -1,6 +1,7 @@ +#![cfg(feature = "preserve_order")] + use async_trait::async_trait; use config::*; -use linked_hash_map::LinkedHashMap; use std::{env, fs, path, str::FromStr}; use tokio::{fs::File, io::AsyncReadExt}; @@ -19,7 +20,7 @@ impl AsyncFile { #[async_trait] impl AsyncSource for AsyncFile { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { let mut path = env::current_dir().unwrap(); let local = path::PathBuf::from_str(&self.path).unwrap(); diff --git a/tests/errors.rs b/tests/errors.rs index 703dddd8..9004cbe2 100644 --- a/tests/errors.rs +++ b/tests/errors.rs @@ -1,11 +1,10 @@ -#![cfg(feature = "toml")] +#![cfg(all(feature = "toml", feature = "preserve_order"))] extern crate config; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -97,7 +96,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/file_hjson.rs b/tests/file_hjson.rs index 376993f1..4439d313 100644 --- a/tests/file_hjson.rs +++ b/tests/file_hjson.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } diff --git a/tests/file_json.rs b/tests/file_json.rs index c3ebe069..035403cd 100644 --- a/tests/file_json.rs +++ b/tests/file_json.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -59,17 +58,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/file_json5.rs b/tests/file_json5.rs index f92bce52..cb04718d 100644 --- a/tests/file_json5.rs +++ b/tests/file_json5.rs @@ -9,7 +9,6 @@ extern crate serde_derive; use config::*; use float_cmp::ApproxEqUlps; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; #[derive(Debug, Deserialize)] @@ -20,7 +19,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -58,17 +57,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/file_ron.rs b/tests/file_ron.rs index 71b9106e..e1351b41 100644 --- a/tests/file_ron.rs +++ b/tests/file_ron.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -22,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -61,17 +60,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/file_toml.rs b/tests/file_toml.rs index 77d4d31d..c0bcb31b 100644 --- a/tests/file_toml.rs +++ b/tests/file_toml.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -22,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -70,17 +69,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/file_yaml.rs b/tests/file_yaml.rs index 4b1c1088..18e34ad7 100644 --- a/tests/file_yaml.rs +++ b/tests/file_yaml.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use config::*; @@ -21,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -59,17 +58,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/get.rs b/tests/get.rs index 43a126a8..9cd6eccb 100644 --- a/tests/get.rs +++ b/tests/get.rs @@ -7,7 +7,6 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use linked_hash_map::LinkedHashMap; use std::collections::HashSet; use config::*; @@ -108,7 +107,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: LinkedHashMap = c.get("place").unwrap(); + let m: MapImpl = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -121,23 +120,28 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: LinkedHashMap = c.get("place.creator").unwrap(); - - assert_eq!( - m.into_iter().collect::>(), - vec![ - ("name".to_string(), "John Smith".to_string()), - ("username".to_string(), "jsmith".to_string()), - ("email".to_string(), "jsmith@localhost".to_string()), - ] - ); + let m: MapImpl = c.get("place.creator").unwrap(); + + if cfg!(feature = "preserve_order") { + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "John Smith".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); + } else { + assert_eq!(m.len(), 3); + assert_eq!(m["name"], "John Smith".to_string()); + } } #[test] fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: LinkedHashMap, + place: MapImpl, } let c = make(); @@ -222,7 +226,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: LinkedHashMap, + diodes: MapImpl, } let c = make(); @@ -255,7 +259,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: LinkedHashMap, + proton: MapImpl, // Just to make sure that set keys work too. quarks: HashSet, } @@ -271,7 +275,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: LinkedHashMap, + divisors: MapImpl, } let c = make(); diff --git a/tests/legacy/errors.rs b/tests/legacy/errors.rs index 070eb6d8..4da586ea 100644 --- a/tests/legacy/errors.rs +++ b/tests/legacy/errors.rs @@ -2,7 +2,6 @@ extern crate config; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -94,7 +93,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/legacy/file_hjson.rs b/tests/legacy/file_hjson.rs index b846c919..8ca2d687 100644 --- a/tests/legacy/file_hjson.rs +++ b/tests/legacy/file_hjson.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } diff --git a/tests/legacy/file_json.rs b/tests/legacy/file_json.rs index 6a9b5770..2486a553 100644 --- a/tests/legacy/file_json.rs +++ b/tests/legacy/file_json.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -57,17 +56,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/legacy/file_ron.rs b/tests/legacy/file_ron.rs index bfd31af7..19b629d0 100644 --- a/tests/legacy/file_ron.rs +++ b/tests/legacy/file_ron.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -19,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -59,17 +58,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/legacy/file_toml.rs b/tests/legacy/file_toml.rs index 24c590eb..53310b47 100644 --- a/tests/legacy/file_toml.rs +++ b/tests/legacy/file_toml.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -19,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -68,17 +67,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/legacy/file_yaml.rs b/tests/legacy/file_yaml.rs index af04ef62..572e10c4 100644 --- a/tests/legacy/file_yaml.rs +++ b/tests/legacy/file_yaml.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::path::PathBuf; use self::config::*; @@ -18,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: LinkedHashMap, + creator: MapImpl, rating: Option, } @@ -57,17 +56,24 @@ fn test_file() { assert_eq!(s.place.telephone, None); assert_eq!(s.elements.len(), 10); assert_eq!(s.elements[3], "4".to_string()); - assert_eq!( - s.place - .creator - .into_iter() - .collect::>(), - vec![ - ("name".to_string(), "John Smith".into()), - ("username".into(), "jsmith".into()), - ("email".into(), "jsmith@localhost".into()), - ] - ); + if cfg!(feature = "preserve_order") { + assert_eq!( + s.place + .creator + .into_iter() + .collect::>(), + vec![ + ("name".to_string(), "John Smith".into()), + ("username".into(), "jsmith".into()), + ("email".into(), "jsmith@localhost".into()), + ] + ); + } else { + assert_eq!( + s.place.creator["name"].clone().into_string().unwrap(), + "John Smith".to_string() + ); + } } #[test] diff --git a/tests/legacy/get.rs b/tests/legacy/get.rs index c2465676..6b12a57f 100644 --- a/tests/legacy/get.rs +++ b/tests/legacy/get.rs @@ -4,7 +4,6 @@ extern crate config; extern crate float_cmp; extern crate serde; -use linked_hash_map::LinkedHashMap; use std::collections::HashSet; use self::config::*; @@ -106,7 +105,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: LinkedHashMap = c.get("place").unwrap(); + let m: MapImpl = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -119,23 +118,28 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: LinkedHashMap = c.get("place.creator").unwrap(); - - assert_eq!( - m.into_iter().collect::>(), - vec![ - ("name".to_string(), "John Smith".to_string()), - ("username".to_string(), "jsmith".to_string()), - ("email".to_string(), "jsmith@localhost".to_string()), - ] - ); + let m: MapImpl = c.get("place.creator").unwrap(); + + if cfg!(feature = "preserve_order") { + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "John Smith".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); + } else { + assert_eq!(m.len(), 3); + assert_eq!(m["name"], "John Smith".to_string()); + } } #[test] fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: LinkedHashMap, + place: MapImpl, } let c = make(); @@ -220,7 +224,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: LinkedHashMap, + diodes: MapImpl, } let c = make(); @@ -253,7 +257,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: LinkedHashMap, + proton: MapImpl, // Just to make sure that set keys work too. quarks: HashSet, } @@ -269,7 +273,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: LinkedHashMap, + divisors: MapImpl, } let c = make(); diff --git a/tests/legacy/merge.rs b/tests/legacy/merge.rs index 75cb16d5..d93724d3 100644 --- a/tests/legacy/merge.rs +++ b/tests/legacy/merge.rs @@ -3,7 +3,6 @@ extern crate config; use self::config::*; -use linked_hash_map::LinkedHashMap; fn make() -> Config { let mut c = Config::default(); @@ -24,15 +23,22 @@ fn test_merge() { assert_eq!(c.get("production").ok(), Some(true)); assert_eq!(c.get("place.rating").ok(), Some(4.9)); - let m: LinkedHashMap = c.get("place.creator").unwrap(); - assert_eq!( - m.into_iter().collect::>(), - vec![ - ("name".to_string(), "Somebody New".to_string()), - ("username".to_string(), "jsmith".to_string()), - ("email".to_string(), "jsmith@localhost".to_string()), - ] - ); + if cfg!(feature = "preserve_order") { + let m: MapImpl = c.get("place.creator").unwrap(); + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "Somebody New".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); + } else { + assert_eq!( + c.get("place.creator.name").ok(), + Some("Somebody New".to_string()) + ); + } } #[test] diff --git a/tests/merge.rs b/tests/merge.rs index 922ae317..93e2f397 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -3,7 +3,6 @@ extern crate config; use config::*; -use linked_hash_map::LinkedHashMap; fn make() -> Config { Config::builder() @@ -21,15 +20,22 @@ fn test_merge() { assert_eq!(c.get("production").ok(), Some(true)); assert_eq!(c.get("place.rating").ok(), Some(4.9)); - let m: LinkedHashMap = c.get("place.creator").unwrap(); - assert_eq!( - m.into_iter().collect::>(), - vec![ - ("name".to_string(), "Somebody New".to_string()), - ("username".to_string(), "jsmith".to_string()), - ("email".to_string(), "jsmith@localhost".to_string()), - ] - ); + if cfg!(feature = "preserve_order") { + let m: MapImpl = c.get("place.creator").unwrap(); + assert_eq!( + m.into_iter().collect::>(), + vec![ + ("name".to_string(), "Somebody New".to_string()), + ("username".to_string(), "jsmith".to_string()), + ("email".to_string(), "jsmith@localhost".to_string()), + ] + ); + } else { + assert_eq!( + c.get("place.creator.name").ok(), + Some("Somebody New".to_string()) + ); + } } #[test] From ea62693f6fff0dd24865b934334260d06f190e01 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Sun, 1 Aug 2021 00:11:40 -0700 Subject: [PATCH 07/10] Switch from LinkedHashMap to IndexMap --- Cargo.toml | 4 ++-- src/builder.rs | 1 - src/map.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8d76ba08..d530d06b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ yaml = ["yaml-rust"] hjson = ["serde-hjson"] ini = ["rust-ini"] json5 = ["json5_rs"] -preserve_order = ["linked-hash-map", "toml/preserve_order", "serde_json/preserve_order", "ron/indexmap"] +preserve_order = ["indexmap", "toml/preserve_order", "serde_json/preserve_order", "ron/indexmap"] [dependencies] async-trait = "0.1.50" @@ -36,7 +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" } -linked-hash-map = { version = "0.5.4", optional = true, features = ["serde_impl"] } +indexmap = { version = "1.7.0", features = ["serde-1"], optional = true} [dev-dependencies] serde_derive = "1.0.8" diff --git a/src/builder.rs b/src/builder.rs index 5100f5f5..0cbd32a1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,7 +1,6 @@ use std::iter::IntoIterator; use std::str::FromStr; - use crate::error::Result; use crate::map::MapImpl; use crate::source::AsyncSource; diff --git a/src/map.rs b/src/map.rs index ae41155e..baf4e3b7 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,4 +1,4 @@ #[cfg(not(feature = "preserve_order"))] pub type MapImpl = std::collections::HashMap; #[cfg(feature = "preserve_order")] -pub type MapImpl = linked_hash_map::LinkedHashMap; +pub type MapImpl = indexmap::IndexMap; From 0e0ae2b359b5c943055c988c3c78f36db2503468 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Mon, 2 Aug 2021 23:15:59 -0700 Subject: [PATCH 08/10] Remove unnecessary uses for feature/map --- src/file/format/mod.rs | 5 +++-- tests/async_builder.rs | 2 -- tests/errors.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/file/format/mod.rs b/src/file/format/mod.rs index df59ca61..640ef28d 100644 --- a/src/file/format/mod.rs +++ b/src/file/format/mod.rs @@ -2,6 +2,7 @@ // BUG: ? For some reason this doesn't do anything if I try and function scope this #![allow(unused_mut)] +use std::collections::HashMap; use std::error::Error; use crate::map::MapImpl; @@ -62,8 +63,8 @@ pub enum FileFormat { lazy_static! { #[doc(hidden)] // #[allow(unused_mut)] ? - pub static ref ALL_EXTENSIONS: MapImpl> = { - let mut formats: MapImpl> = MapImpl::new(); + pub static ref ALL_EXTENSIONS: HashMap> = { + let mut formats: HashMap> = HashMap::new(); #[cfg(feature = "toml")] formats.insert(FileFormat::Toml, vec!["toml"]); diff --git a/tests/async_builder.rs b/tests/async_builder.rs index bf923d61..08bf6916 100644 --- a/tests/async_builder.rs +++ b/tests/async_builder.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "preserve_order")] - use async_trait::async_trait; use config::*; use std::{env, fs, path, str::FromStr}; diff --git a/tests/errors.rs b/tests/errors.rs index 9004cbe2..f3f201a2 100644 --- a/tests/errors.rs +++ b/tests/errors.rs @@ -1,4 +1,4 @@ -#![cfg(all(feature = "toml", feature = "preserve_order"))] +#![cfg(feature = "toml")] extern crate config; From be82af2a474b9c6ac85ec1e001af1704521820e6 Mon Sep 17 00:00:00 2001 From: David Orchard Date: Mon, 2 Aug 2021 23:17:08 -0700 Subject: [PATCH 09/10] Rename MapImpl to Map --- examples/async_source/main.rs | 4 ++-- examples/glob/src/main.rs | 14 +++++++------- examples/simple/src/main.rs | 6 +++--- examples/watch/src/main.rs | 4 ++-- src/builder.rs | 22 +++++++++++----------- src/config.rs | 12 ++++++------ src/de.rs | 4 ++-- src/env.rs | 6 +++--- src/file/format/hjson.rs | 8 ++++---- src/file/format/ini.rs | 8 ++++---- src/file/format/json.rs | 8 ++++---- src/file/format/json5.rs | 8 ++++---- src/file/format/mod.rs | 4 ++-- src/file/format/ron.rs | 8 ++++---- src/file/format/toml.rs | 8 ++++---- src/file/format/yaml.rs | 8 ++++---- src/file/mod.rs | 6 +++--- src/lib.rs | 2 +- src/map.rs | 4 ++-- src/path/mod.rs | 10 +++++----- src/source.rs | 22 +++++++++++----------- src/value.rs | 10 +++++----- tests/async_builder.rs | 2 +- tests/errors.rs | 2 +- tests/file_hjson.rs | 2 +- tests/file_json.rs | 2 +- tests/file_json5.rs | 2 +- tests/file_ron.rs | 2 +- tests/file_toml.rs | 2 +- tests/file_yaml.rs | 2 +- tests/get.rs | 12 ++++++------ tests/legacy/errors.rs | 2 +- tests/legacy/file_hjson.rs | 2 +- tests/legacy/file_json.rs | 2 +- tests/legacy/file_ron.rs | 2 +- tests/legacy/file_toml.rs | 2 +- tests/legacy/file_yaml.rs | 2 +- tests/legacy/get.rs | 12 ++++++------ tests/legacy/merge.rs | 2 +- tests/merge.rs | 2 +- 40 files changed, 121 insertions(+), 121 deletions(-) diff --git a/examples/async_source/main.rs b/examples/async_source/main.rs index 51348224..005a4737 100644 --- a/examples/async_source/main.rs +++ b/examples/async_source/main.rs @@ -1,6 +1,6 @@ use std::error::Error; -use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat, MapImpl}; +use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat, Map}; use async_trait::async_trait; use futures::{select, FutureExt}; @@ -56,7 +56,7 @@ struct HttpSource { #[async_trait] impl AsyncSource for HttpSource { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { reqwest::get(&self.uri) .await .map_err(|e| ConfigError::Foreign(Box::new(e)))? // error conversion is possible from custom AsyncSource impls diff --git a/examples/glob/src/main.rs b/examples/glob/src/main.rs index d429917d..002ddd4f 100644 --- a/examples/glob/src/main.rs +++ b/examples/glob/src/main.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::collections::MapImpl; +use std::collections::Map; use config::*; use glob::glob; @@ -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 MapImpl) + // Print out our settings (as a Map) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 2 // -------- @@ -28,9 +28,9 @@ fn main() { File::from(Path::new("conf/99-extra.json"))]) .unwrap(); - // Print out our settings (as a MapImpl) + // Print out our settings (as a Map) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); // Option 3 // -------- @@ -43,7 +43,7 @@ fn main() { .collect::>()) .unwrap(); - // Print out our settings (as a MapImpl) + // Print out our settings (as a Map) println!("\n{:?} \n\n-----------", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index 5d4c3bc6..e07eff28 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -1,4 +1,4 @@ -use std::collections::MapImpl; +use std::collections::Map; fn main() { let mut settings = config::Config::default(); @@ -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 MapImpl) + // Print out our settings (as a Map) println!("{:?}", - settings.try_into::>().unwrap()); + settings.try_into::>().unwrap()); } diff --git a/examples/watch/src/main.rs b/examples/watch/src/main.rs index fed4ed04..cbe30e72 100644 --- a/examples/watch/src/main.rs +++ b/examples/watch/src/main.rs @@ -1,5 +1,5 @@ use config::*; -use std::collections::MapImpl; +use std::collections::Map; use std::sync::RwLock; use notify::{RecommendedWatcher, DebouncedEvent, Watcher, RecursiveMode}; use std::sync::mpsc::channel; @@ -20,7 +20,7 @@ fn show() { .read() .unwrap() .clone() - .try_into::>() + .try_into::>() .unwrap()); } diff --git a/src/builder.rs b/src/builder.rs index 0cbd32a1..e6296060 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2,7 +2,7 @@ use std::iter::IntoIterator; use std::str::FromStr; use crate::error::Result; -use crate::map::MapImpl; +use crate::map::Map; use crate::source::AsyncSource; use crate::{config::Config, path::Expression, source::Source, value::Value}; @@ -88,8 +88,8 @@ use crate::{config::Config, path::Expression, source::Source, value::Value}; /// ``` #[derive(Debug, Clone, Default)] pub struct ConfigBuilder { - defaults: MapImpl, - overrides: MapImpl, + defaults: Map, + overrides: Map, state: St, } @@ -121,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: MapImpl, - overrides: MapImpl, + defaults: Map, + overrides: Map, sources: Vec, } @@ -245,11 +245,11 @@ impl ConfigBuilder { } fn build_internal( - defaults: MapImpl, - overrides: MapImpl, + defaults: Map, + overrides: Map, sources: &[Box], ) -> Result { - let mut cache: Value = MapImpl::::new().into(); + let mut cache: Value = Map::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { @@ -323,11 +323,11 @@ impl ConfigBuilder { } async fn build_internal( - defaults: MapImpl, - overrides: MapImpl, + defaults: Map, + overrides: Map, sources: &[SourceType], ) -> Result { - let mut cache: Value = MapImpl::::new().into(); + let mut cache: Value = Map::::new().into(); // Add defaults for (key, val) in defaults.into_iter() { diff --git a/src/config.rs b/src/config.rs index 8c410f08..55844ce6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ use serde::de::Deserialize; use serde::ser::Serialize; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::path; use crate::ser::ConfigSerializer; use crate::source::Source; @@ -16,8 +16,8 @@ use crate::value::{Table, Value}; /// them according to the source's priority. #[derive(Clone, Debug)] pub struct Config { - defaults: MapImpl, - overrides: MapImpl, + defaults: Map, + overrides: Map, sources: Vec>, /// Root of the cached configuration. @@ -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 = MapImpl::::new().into(); + let mut cache: Value = Map::::new().into(); // Add defaults for (key, val) in self.defaults.iter() { @@ -181,7 +181,7 @@ impl Config { self.get(key).and_then(Value::into_bool) } - pub fn get_table(&self, key: &str) -> Result> { + pub fn get_table(&self, key: &str) -> Result> { self.get(key).and_then(Value::into_table) } @@ -212,7 +212,7 @@ impl Source for Config { Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { self.cache.clone().into_table() } } diff --git a/src/de.rs b/src/de.rs index 9aa6b45b..60fa4eaa 100644 --- a/src/de.rs +++ b/src/de.rs @@ -5,7 +5,7 @@ use serde::de; use crate::config::Config; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Table, Value, ValueKind}; impl<'de> de::Deserializer<'de> for Value { @@ -200,7 +200,7 @@ struct MapAccess { } impl MapAccess { - fn new(table: MapImpl) -> Self { + fn new(table: Map) -> Self { MapAccess { elements: table.into_iter().collect(), } diff --git a/src/env.rs b/src/env.rs index 507ace64..736d584c 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,7 +1,7 @@ use std::env; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::source::Source; use crate::value::{Value, ValueKind}; @@ -79,8 +79,8 @@ impl Source for Environment { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut m = MapImpl::new(); + fn collect(&self) -> Result> { + let mut m = Map::new(); let uri: String = "the environment".into(); let separator = self.separator.as_deref().unwrap_or(""); diff --git a/src/file/format/hjson.rs b/src/file/format/hjson.rs index 68b9c9c9..4b761149 100644 --- a/src/file/format/hjson.rs +++ b/src/file/format/hjson.rs @@ -1,19 +1,19 @@ use std::error::Error; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(MapImpl::new()), + _ => Ok(Map::new()), } } @@ -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 = MapImpl::new(); + let mut m = Map::new(); for (key, value) in table { m.insert(key.clone(), from_hjson_value(uri, value)); diff --git a/src/file/format/ini.rs b/src/file/format/ini.rs index b5f742d5..9295e60e 100644 --- a/src/file/format/ini.rs +++ b/src/file/format/ini.rs @@ -2,19 +2,19 @@ use std::error::Error; use ini::Ini; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { - let mut map: MapImpl = MapImpl::new(); +) -> Result, Box> { + let mut map: Map = Map::new(); let i = Ini::load_from_str(text)?; for (sec, prop) in i.iter() { match sec { Some(sec) => { - let mut sec_map: MapImpl = MapImpl::new(); + let mut sec_map: Map = Map::new(); for (k, v) in prop.iter() { sec_map.insert( k.to_owned(), diff --git a/src/file/format/json.rs b/src/file/format/json.rs index c4895fb6..e3d8b874 100644 --- a/src/file/format/json.rs +++ b/src/file/format/json.rs @@ -1,19 +1,19 @@ use std::error::Error; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // 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(MapImpl::new()), + _ => Ok(Map::new()), } } @@ -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 = MapImpl::new(); + let mut m = Map::new(); for (key, value) in table { m.insert(key.clone(), from_json_value(uri, value)); diff --git a/src/file/format/json5.rs b/src/file/format/json5.rs index 69432c01..c1567975 100644 --- a/src/file/format/json5.rs +++ b/src/file/format/json5.rs @@ -1,7 +1,7 @@ use std::error::Error; use crate::error::{ConfigError, Unexpected}; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; #[derive(serde::Deserialize, Debug)] @@ -13,13 +13,13 @@ pub enum Val { Float(f64), String(String), Array(Vec), - Object(MapImpl), + Object(Map), } pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { match json5_rs::from_str::(text)? { Val::String(ref value) => Err(Unexpected::Str(value.clone())), Val::Integer(value) => Err(Unexpected::Integer(value)), @@ -29,7 +29,7 @@ pub fn parse( Val::Null => Err(Unexpected::Unit), Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind { ValueKind::Table(map) => Ok(map), - _ => Ok(MapImpl::new()), + _ => Ok(Map::new()), }, } .map_err(|err| ConfigError::invalid_root(uri, err)) diff --git a/src/file/format/mod.rs b/src/file/format/mod.rs index 640ef28d..9f6d7d73 100644 --- a/src/file/format/mod.rs +++ b/src/file/format/mod.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::error::Error; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::Value; #[cfg(feature = "toml")] @@ -108,7 +108,7 @@ impl FileFormat { self, uri: Option<&String>, text: &str, - ) -> Result, Box> { + ) -> Result, Box> { match self { #[cfg(feature = "toml")] FileFormat::Toml => toml::parse(uri, text), diff --git a/src/file/format/ron.rs b/src/file/format/ron.rs index 769fd538..3fb2a0fc 100644 --- a/src/file/format/ron.rs +++ b/src/file/format/ron.rs @@ -1,17 +1,17 @@ use std::error::Error; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { let value = from_ron_value(uri, ron::from_str(text)?)?; match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(MapImpl::new()), + _ => Ok(Map::new()), } } @@ -56,7 +56,7 @@ fn from_ron_value( Ok((key, value)) }) - .collect::, _>>()?; + .collect::, _>>()?; ValueKind::Table(map) } diff --git a/src/file/format/toml.rs b/src/file/format/toml.rs index a4e16b2b..af21fc78 100644 --- a/src/file/format/toml.rs +++ b/src/file/format/toml.rs @@ -1,19 +1,19 @@ use std::error::Error; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a TOML value from the provided text // TODO: Have a proper error fire if the root of a file is ever not a Table let value = from_toml_value(uri, &toml::from_str(text)?); match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(MapImpl::new()), + _ => Ok(Map::new()), } } @@ -25,7 +25,7 @@ fn from_toml_value(uri: Option<&String>, value: &toml::Value) -> Value { toml::Value::Boolean(value) => Value::new(uri, value), toml::Value::Table(ref table) => { - let mut m = MapImpl::new(); + let mut m = Map::new(); for (key, value) in table { m.insert(key.clone(), from_toml_value(uri, value)); diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs index f725b1f1..44b72fbc 100644 --- a/src/file/format/yaml.rs +++ b/src/file/format/yaml.rs @@ -4,13 +4,13 @@ use std::mem; use yaml_rust as yaml; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, -) -> Result, Box> { +) -> Result, Box> { // Parse a YAML object from file let mut docs = yaml::YamlLoader::load_from_str(text)?; let root = match docs.len() { @@ -26,7 +26,7 @@ pub fn parse( match value.kind { ValueKind::Table(map) => Ok(map), - _ => Ok(MapImpl::new()), + _ => Ok(Map::new()), } } @@ -40,7 +40,7 @@ fn from_yaml_value(uri: Option<&String>, value: &yaml::Yaml) -> Value { yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::Integer(value)), yaml::Yaml::Boolean(value) => Value::new(uri, ValueKind::Boolean(value)), yaml::Yaml::Hash(ref table) => { - let mut m = MapImpl::new(); + let mut m = Map::new(); for (key, value) in table { if let Some(k) = key.as_str() { m.insert(k.to_owned(), from_yaml_value(uri, value)); diff --git a/src/file/mod.rs b/src/file/mod.rs index d5744f48..0160d7ce 100644 --- a/src/file/mod.rs +++ b/src/file/mod.rs @@ -4,7 +4,7 @@ pub mod source; use std::path::{Path, PathBuf}; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::source::Source; use crate::value::Value; @@ -99,7 +99,7 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { + fn collect(&self) -> Result> { // Coerce the file contents to a string let (uri, contents, format) = match self .source @@ -110,7 +110,7 @@ where Err(error) => { if !self.required { - return Ok(MapImpl::new()); + return Ok(Map::new()); } return Err(error); diff --git a/src/lib.rs b/src/lib.rs index 511ddd87..267e0d8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ pub use crate::config::Config; pub use crate::env::Environment; pub use crate::error::ConfigError; pub use crate::file::{File, FileFormat, FileSourceFile, FileSourceString}; -pub use crate::map::MapImpl; +pub use crate::map::Map; pub use crate::source::AsyncSource; pub use crate::source::Source; pub use crate::value::Value; diff --git a/src/map.rs b/src/map.rs index baf4e3b7..5873f0d2 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,4 +1,4 @@ #[cfg(not(feature = "preserve_order"))] -pub type MapImpl = std::collections::HashMap; +pub type Map = std::collections::HashMap; #[cfg(feature = "preserve_order")] -pub type MapImpl = indexmap::IndexMap; +pub type Map = indexmap::IndexMap; diff --git a/src/path/mod.rs b/src/path/mod.rs index 8ce51f96..cd7ccd74 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::value::{Value, ValueKind}; mod parser; @@ -135,7 +135,7 @@ impl Expression { ), _ => { - *value = MapImpl::::new().into(); + *value = Map::::new().into(); if let ValueKind::Table(ref mut map) = value.kind { Some( @@ -186,7 +186,7 @@ impl Expression { ValueKind::Table(_) => {} _ => { - *root = MapImpl::::new().into(); + *root = Map::::new().into(); } } @@ -195,7 +195,7 @@ impl Expression { // Pull out another table let mut target = if let ValueKind::Table(ref mut map) = root.kind { map.entry(id.clone()) - .or_insert_with(|| MapImpl::::new().into()) + .or_insert_with(|| Map::::new().into()) } else { unreachable!(); }; @@ -228,7 +228,7 @@ impl Expression { _ => { // Didn't find a table. Oh well. Make a table and do this anyway - *parent = MapImpl::::new().into(); + *parent = Map::::new().into(); Expression::Identifier(key.clone()).set(parent, value); } diff --git a/src/source.rs b/src/source.rs index 2c763668..0faf6d10 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use async_trait::async_trait; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; use crate::path; use crate::value::{Value, ValueKind}; @@ -13,8 +13,8 @@ pub trait Source: Debug { fn clone_into_box(&self) -> Box; /// Collect all configuration properties available from this source and return - /// a MapImpl. - fn collect(&self) -> Result>; + /// a Map. + fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -55,8 +55,8 @@ pub trait AsyncSource: Debug + Sync { // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits /// Collects all configuration properties available from this source and return - /// a MapImpl as an async operations. - async fn collect(&self) -> Result>; + /// a Map as an async operations. + async fn collect(&self) -> Result>; /// Collects all configuration properties to a provided cache. async fn collect_to(&self, cache: &mut Value) -> Result<()> { @@ -86,8 +86,8 @@ impl Source for Vec> { Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = MapImpl::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = Map::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -106,8 +106,8 @@ impl Source for [Box] { Box::new(self.to_owned()) } - fn collect(&self) -> Result> { - let mut cache: Value = MapImpl::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = Map::::new().into(); for source in self { source.collect_to(&mut cache)?; @@ -131,8 +131,8 @@ where Box::new((*self).clone()) } - fn collect(&self) -> Result> { - let mut cache: Value = MapImpl::::new().into(); + fn collect(&self) -> Result> { + let mut cache: Value = Map::::new().into(); for source in self { source.collect_to(&mut cache)?; diff --git a/src/value.rs b/src/value.rs index 17be54d9..1523c1e5 100644 --- a/src/value.rs +++ b/src/value.rs @@ -4,7 +4,7 @@ use std::fmt::Display; use serde::de::{Deserialize, Deserializer, Visitor}; use crate::error::*; -use crate::map::MapImpl; +use crate::map::Map; /// Underlying kind of the configuration value. /// @@ -23,7 +23,7 @@ pub enum ValueKind { } pub type Array = Vec; -pub type Table = MapImpl; +pub type Table = Map; impl Default for ValueKind { fn default() -> Self { @@ -73,11 +73,11 @@ impl From for ValueKind { } } -impl From> for ValueKind +impl From> for ValueKind where T: Into, { - fn from(values: MapImpl) -> Self { + fn from(values: Map) -> Self { let t = values.into_iter().map(|(k, v)| (k, v.into())).collect(); ValueKind::Table(t) } @@ -357,7 +357,7 @@ impl Value { /// If the `Value` is a Table, returns the associated Map. // FIXME: Should this not be `try_into_*` ? - pub fn into_table(self) -> Result> { + pub fn into_table(self) -> Result> { match self.kind { ValueKind::Table(value) => Ok(value), diff --git a/tests/async_builder.rs b/tests/async_builder.rs index 08bf6916..b0aa0f4f 100644 --- a/tests/async_builder.rs +++ b/tests/async_builder.rs @@ -18,7 +18,7 @@ impl AsyncFile { #[async_trait] impl AsyncSource for AsyncFile { - async fn collect(&self) -> Result, ConfigError> { + async fn collect(&self) -> Result, ConfigError> { let mut path = env::current_dir().unwrap(); let local = path::PathBuf::from_str(&self.path).unwrap(); diff --git a/tests/errors.rs b/tests/errors.rs index f3f201a2..60f11211 100644 --- a/tests/errors.rs +++ b/tests/errors.rs @@ -96,7 +96,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/file_hjson.rs b/tests/file_hjson.rs index 4439d313..4ac2e120 100644 --- a/tests/file_hjson.rs +++ b/tests/file_hjson.rs @@ -20,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/file_json.rs b/tests/file_json.rs index 035403cd..d3fa0a91 100644 --- a/tests/file_json.rs +++ b/tests/file_json.rs @@ -20,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/file_json5.rs b/tests/file_json5.rs index cb04718d..a768bba0 100644 --- a/tests/file_json5.rs +++ b/tests/file_json5.rs @@ -19,7 +19,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/file_ron.rs b/tests/file_ron.rs index e1351b41..32c71923 100644 --- a/tests/file_ron.rs +++ b/tests/file_ron.rs @@ -21,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/file_toml.rs b/tests/file_toml.rs index c0bcb31b..b6bb5375 100644 --- a/tests/file_toml.rs +++ b/tests/file_toml.rs @@ -21,7 +21,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/file_yaml.rs b/tests/file_yaml.rs index 18e34ad7..c87d5e97 100644 --- a/tests/file_yaml.rs +++ b/tests/file_yaml.rs @@ -20,7 +20,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/get.rs b/tests/get.rs index 9cd6eccb..cc9befbd 100644 --- a/tests/get.rs +++ b/tests/get.rs @@ -107,7 +107,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: MapImpl = c.get("place").unwrap(); + let m: Map = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -120,7 +120,7 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: MapImpl = c.get("place.creator").unwrap(); + let m: Map = c.get("place.creator").unwrap(); if cfg!(feature = "preserve_order") { assert_eq!( @@ -141,7 +141,7 @@ fn test_map_str() { fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: MapImpl, + place: Map, } let c = make(); @@ -226,7 +226,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: MapImpl, + diodes: Map, } let c = make(); @@ -259,7 +259,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: MapImpl, + proton: Map, // Just to make sure that set keys work too. quarks: HashSet, } @@ -275,7 +275,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: MapImpl, + divisors: Map, } let c = make(); diff --git a/tests/legacy/errors.rs b/tests/legacy/errors.rs index 4da586ea..c0ce234d 100644 --- a/tests/legacy/errors.rs +++ b/tests/legacy/errors.rs @@ -93,7 +93,7 @@ fn test_error_enum_de() { ] .iter() .cloned() - .collect::>() + .collect::>() .into(); let confused_d = confused_v.try_into::(); assert_eq!( diff --git a/tests/legacy/file_hjson.rs b/tests/legacy/file_hjson.rs index 8ca2d687..8801a131 100644 --- a/tests/legacy/file_hjson.rs +++ b/tests/legacy/file_hjson.rs @@ -17,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/legacy/file_json.rs b/tests/legacy/file_json.rs index 2486a553..b2294b07 100644 --- a/tests/legacy/file_json.rs +++ b/tests/legacy/file_json.rs @@ -17,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/legacy/file_ron.rs b/tests/legacy/file_ron.rs index 19b629d0..ea8bc272 100644 --- a/tests/legacy/file_ron.rs +++ b/tests/legacy/file_ron.rs @@ -18,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/legacy/file_toml.rs b/tests/legacy/file_toml.rs index 53310b47..b8a1337d 100644 --- a/tests/legacy/file_toml.rs +++ b/tests/legacy/file_toml.rs @@ -18,7 +18,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/legacy/file_yaml.rs b/tests/legacy/file_yaml.rs index 572e10c4..818518b4 100644 --- a/tests/legacy/file_yaml.rs +++ b/tests/legacy/file_yaml.rs @@ -17,7 +17,7 @@ struct Place { favorite: bool, telephone: Option, reviews: u64, - creator: MapImpl, + creator: Map, rating: Option, } diff --git a/tests/legacy/get.rs b/tests/legacy/get.rs index 6b12a57f..061e35e6 100644 --- a/tests/legacy/get.rs +++ b/tests/legacy/get.rs @@ -105,7 +105,7 @@ fn test_get_scalar_path_subscript() { #[test] fn test_map() { let c = make(); - let m: MapImpl = c.get("place").unwrap(); + let m: Map = c.get("place").unwrap(); assert_eq!(m.len(), 8); assert_eq!( @@ -118,7 +118,7 @@ fn test_map() { #[test] fn test_map_str() { let c = make(); - let m: MapImpl = c.get("place.creator").unwrap(); + let m: Map = c.get("place.creator").unwrap(); if cfg!(feature = "preserve_order") { assert_eq!( @@ -139,7 +139,7 @@ fn test_map_str() { fn test_map_struct() { #[derive(Debug, Deserialize)] struct Settings { - place: MapImpl, + place: Map, } let c = make(); @@ -224,7 +224,7 @@ fn test_enum() { } #[derive(Debug, Deserialize)] struct Settings { - diodes: MapImpl, + diodes: Map, } let c = make(); @@ -257,7 +257,7 @@ fn test_enum_key() { #[derive(Debug, Deserialize)] struct Settings { - proton: MapImpl, + proton: Map, // Just to make sure that set keys work too. quarks: HashSet, } @@ -273,7 +273,7 @@ fn test_enum_key() { fn test_int_key() { #[derive(Debug, Deserialize, PartialEq)] struct Settings { - divisors: MapImpl, + divisors: Map, } let c = make(); diff --git a/tests/legacy/merge.rs b/tests/legacy/merge.rs index d93724d3..8f709719 100644 --- a/tests/legacy/merge.rs +++ b/tests/legacy/merge.rs @@ -24,7 +24,7 @@ fn test_merge() { assert_eq!(c.get("place.rating").ok(), Some(4.9)); if cfg!(feature = "preserve_order") { - let m: MapImpl = c.get("place.creator").unwrap(); + let m: Map = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), vec![ diff --git a/tests/merge.rs b/tests/merge.rs index 93e2f397..cbf2993e 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -21,7 +21,7 @@ fn test_merge() { assert_eq!(c.get("place.rating").ok(), Some(4.9)); if cfg!(feature = "preserve_order") { - let m: MapImpl = c.get("place.creator").unwrap(); + let m: Map = c.get("place.creator").unwrap(); assert_eq!( m.into_iter().collect::>(), vec![ From 9075ca9018417f4b15b60f31e5e3aff64009132c Mon Sep 17 00:00:00 2001 From: David Orchard Date: Tue, 3 Aug 2021 22:35:39 -0700 Subject: [PATCH 10/10] Test with all features enabled in CI --- .github/workflows/msrv.yml | 4 +++- Cargo.toml | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 23e80471..3ec7270e 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -63,6 +63,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test + args: --all-features - name: Run cargo test (nightly) if: matrix.rust == '1.46.0' @@ -70,7 +71,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --tests + args: --tests --all-features - name: Run cargo test (nightly) if: matrix.rust == 'nightly' @@ -78,6 +79,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test + args: --all-features fmt: needs: [check] diff --git a/Cargo.toml b/Cargo.toml index d530d06b..fcc1c1ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,3 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util warp = "0.3.1" futures = "0.3.15" reqwest = "0.11.3" -# Workaround to activate non-default features for tests: -# https://github.com/rust-lang/cargo/issues/2911 -config = { path = ".", features = ["preserve_order"] }