diff options
-rw-r--r-- | Cargo.toml | 34 | ||||
-rw-r--r-- | examples/basic/Cargo.toml | 7 | ||||
-rw-r--r-- | examples/basic/src/main.rs | 35 | ||||
-rw-r--r-- | examples/file-json/Cargo.toml | 7 | ||||
-rw-r--r-- | examples/file-json/Settings.json | 5 | ||||
-rw-r--r-- | examples/file-json/src/main.rs | 12 | ||||
-rw-r--r-- | examples/file-toml/Cargo.toml | 9 | ||||
-rw-r--r-- | examples/file-toml/Settings.toml | 4 | ||||
-rw-r--r-- | examples/file-toml/src/main.rs | 22 | ||||
-rw-r--r-- | examples/file-yaml/Cargo.toml | 7 | ||||
-rw-r--r-- | examples/file-yaml/Settings.yaml | 3 | ||||
-rw-r--r-- | examples/file-yaml/src/main.rs | 12 | ||||
-rw-r--r-- | lib/Cargo.toml | 24 | ||||
-rw-r--r-- | lib/src/value.rs | 249 | ||||
-rw-r--r-- | src/config.rs (renamed from lib/src/config.rs) | 4 | ||||
-rw-r--r-- | src/de.rs (renamed from lib/src/de.rs) | 74 | ||||
-rw-r--r-- | src/error.rs (renamed from lib/src/error.rs) | 0 | ||||
-rw-r--r-- | src/file/format/mod.rs (renamed from lib/src/file/format/mod.rs) | 0 | ||||
-rw-r--r-- | src/file/format/toml.rs (renamed from lib/src/file/format/toml.rs) | 0 | ||||
-rw-r--r-- | src/file/mod.rs (renamed from lib/src/file/mod.rs) | 0 | ||||
-rw-r--r-- | src/file/source/file.rs (renamed from lib/src/file/source/file.rs) | 0 | ||||
-rw-r--r-- | src/file/source/mod.rs (renamed from lib/src/file/source/mod.rs) | 0 | ||||
-rw-r--r-- | src/file/source/string.rs (renamed from lib/src/file/source/string.rs) | 0 | ||||
-rw-r--r-- | src/lib.rs (renamed from lib/src/lib.rs) | 0 | ||||
-rw-r--r-- | src/path/mod.rs (renamed from lib/src/path/mod.rs) | 4 | ||||
-rw-r--r-- | src/path/parser.rs (renamed from lib/src/path/parser.rs) | 10 | ||||
-rw-r--r-- | src/source.rs (renamed from lib/src/source.rs) | 0 | ||||
-rw-r--r-- | src/value.rs | 328 | ||||
-rw-r--r-- | tests/Settings.toml | 12 | ||||
-rw-r--r-- | tests/scalar.rs | 44 | ||||
-rw-r--r-- | tests/struct.rs | 68 |
31 files changed, 561 insertions, 413 deletions
@@ -1,8 +1,26 @@ -[workspace] -members = [ - "lib", - "examples/basic", - # "examples/file-json", - "examples/file-toml", - # "examples/file-yaml", -] +[package] +name = "config" +version = "0.5.0-pre" +description = "Layered configuration system for Rust applications." +homepage = "https://github.com/mehcode/config-rs" +repository = "https://github.com/mehcode/config-rs" +readme = "README.md" +keywords = ["config", "configuration", "settings", "env", "environment"] +authors = ["Ryan Leckey <leckey.ryan@gmail.com>"] +license = "MIT/Apache-2.0" + +[features] +default = ["toml", "json", "yaml"] +json = ["serde_json"] +yaml = ["yaml-rust"] + +[dependencies] +serde = "^0.9" +nom = "^2.1" + +toml = { version = "^0.3", optional = true } +serde_json = { version = "^0.9", optional = true } +yaml-rust = { version = "^0.3.5", optional = true } + +[dev-dependencies] +serde_derive = "^0.9" diff --git a/examples/basic/Cargo.toml b/examples/basic/Cargo.toml deleted file mode 100644 index 25c3f4d..0000000 --- a/examples/basic/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "basic" -version = "0.1.0" -workspace = "../../" - -[dependencies] -config = { path = "../../lib" } diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs deleted file mode 100644 index 49059ef..0000000 --- a/examples/basic/src/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -extern crate config; - -use config::*; - -fn main() { - let mut c = Config::default(); - - // // Set defaults for `window.width` and `window.height` - // c.set_default("window.title", "Basic").unwrap(); - // c.set_default("window.width", 640).unwrap(); - // c.set_default("window.height", 480).unwrap(); - // c.set_default("debug", true).unwrap(); - - // // Note that you can retrieve the stored values as any type as long - // // as there exists a reasonable conversion - // println!("window.title : {:?}", c.get_str("window.title")); - // println!("window.width : {:?}", c.get_str("window.width")); - // println!("window.width : {:?}", c.get_int("window.width")); - // println!("debug : {:?}", c.get_bool("debug")); - // println!("debug : {:?}", c.get_str("debug")); - // println!("debug : {:?}", c.get_int("debug")); - - // // Attempting to get a value as a type that cannot be reasonably - // // converted to will return None - // println!("window.title : {:?}", c.get_bool("window.title")); - - // // Instead of using a get_* function you can get the variant - // // directly - // println!("debug : {:?}", c.get("debug")); - // println!("debug : {:?}", - // c.get("debug").unwrap().into_int()); - - // // Attempting to get a value that does not exist will return None - // println!("not-found : {:?}", c.get("not-found")); -} diff --git a/examples/file-json/Cargo.toml b/examples/file-json/Cargo.toml deleted file mode 100644 index 1e8765e..0000000 --- a/examples/file-json/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "file-json" -version = "0.1.0" -workspace = "../../" - -[dependencies] -config = { path = "../../lib", default-features = false, features = ["json"] } diff --git a/examples/file-json/Settings.json b/examples/file-json/Settings.json deleted file mode 100644 index 72b28e6..0000000 --- a/examples/file-json/Settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "debug": false, - "pi": 3.14159, - "weight": 150 -} diff --git a/examples/file-json/src/main.rs b/examples/file-json/src/main.rs deleted file mode 100644 index e4ff809..0000000 --- a/examples/file-json/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -extern crate config; - -fn main() { - let mut c = config::Config::new(); - - // Read configuration from "Settings.json" - c.merge(config::File::new("Settings", config::FileFormat::Json)).unwrap(); - - println!("debug = {:?}", c.get("debug")); - println!("pi = {:?}", c.get("pi")); - println!("weight = {:?}", c.get("weight")); -} diff --git a/examples/file-toml/Cargo.toml b/examples/file-toml/Cargo.toml deleted file mode 100644 index 0501895..0000000 --- a/examples/file-toml/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "file-toml" -version = "0.1.0" -workspace = "../../" - -[dependencies] -config = { path = "../../lib", features = ["toml"] } -serde = "^0.9" -serde_derive = "^0.9" diff --git a/examples/file-toml/Settings.toml b/examples/file-toml/Settings.toml deleted file mode 100644 index 21fa1e3..0000000 --- a/examples/file-toml/Settings.toml +++ /dev/null @@ -1,4 +0,0 @@ -debug = true -pi = 3.14159 -weight = 150 -location = { x = 10, y = 30 } diff --git a/examples/file-toml/src/main.rs b/examples/file-toml/src/main.rs deleted file mode 100644 index ddca412..0000000 --- a/examples/file-toml/src/main.rs +++ /dev/null @@ -1,22 +0,0 @@ -extern crate config; - -#[macro_use] -extern crate serde_derive; - -#[derive(Debug, Deserialize)] -struct Point { x: i64, y: i64 } - -fn main() { - let mut c = config::Config::default(); - - // Read configuration from "Settings.toml" - c.merge(config::File::new("Settings", config::FileFormat::Toml)).unwrap(); - - // Simple key access to values - println!("debug = {}", c.get::<bool>("debug").unwrap()); - println!("pi = {}", c.get::<f64>("pi").unwrap()); - println!("weight = {}", c.get::<i64>("weight").unwrap()); - println!("location = {:?}", c.get::<Point>("location").unwrap()); - // println!("location.x = {}", c.get::<Point>("location.x").unwrap()); - // println!("location.y = {}", c.get::<Point>("location.y").unwrap()); -} diff --git a/examples/file-yaml/Cargo.toml b/examples/file-yaml/Cargo.toml deleted file mode 100644 index 4570078..0000000 --- a/examples/file-yaml/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "file-yaml" -version = "0.1.0" -workspace = "../../" - -[dependencies] -config = { path = "../../lib", default-features = false, features = ["yaml"] } diff --git a/examples/file-yaml/Settings.yaml b/examples/file-yaml/Settings.yaml deleted file mode 100644 index d92f6ad..0000000 --- a/examples/file-yaml/Settings.yaml +++ /dev/null @@ -1,3 +0,0 @@ -debug: false -pi: 3.14159 -weight: 150 diff --git a/examples/file-yaml/src/main.rs b/examples/file-yaml/src/main.rs deleted file mode 100644 index 6d72976..0000000 --- a/examples/file-yaml/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -extern crate config; - -fn main() { - let mut c = config::Config::new(); - - // Read configuration from "Settings.yaml" - c.merge(config::File::new("Settings", config::FileFormat::Yaml)).unwrap(); - - println!("debug = {:?}", c.get("debug")); - println!("pi = {:?}", c.get("pi")); - println!("weight = {:?}", c.get("weight")); -} diff --git a/lib/Cargo.toml b/lib/Cargo.toml deleted file mode 100644 index 6b04a8e..0000000 --- a/lib/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "config" -version = "0.5.0-pre" -description = "Layered configuration system for Rust applications." -homepage = "https://github.com/mehcode/config-rs" -repository = "https://github.com/mehcode/config-rs" -readme = "README.md" -keywords = ["config", "configuration", "settings", "env", "environment"] -authors = ["Ryan Leckey <leckey.ryan@gmail.com>"] -license = "MIT/Apache-2.0" -workspace = "../" - -[features] -default = ["toml", "json", "yaml"] -json = ["serde_json"] -yaml = ["yaml-rust"] - -[dependencies] -serde = "^0.9" -nom = "^2.1" - -toml = { version = "^0.3", optional = true } -serde_json = { version = "^0.9", optional = true } -yaml-rust = { version = "^0.3.5", optional = true } diff --git a/lib/src/value.rs b/lib/src/value.rs deleted file mode 100644 index 5b0014a..0000000 --- a/lib/src/value.rs +++ /dev/null @@ -1,249 +0,0 @@ -use std::collections::HashMap; -use std::fmt::Display; -use error::*; - -/// Underlying kind of the configuration value. -#[derive(Debug, Clone)] -pub enum ValueKind { - Nil, - Boolean(bool), - Integer(i64), - Float(f64), - String(String), - Table(Table), - Array(Array), -} - -pub type Array = Vec<Value>; -pub type Table = HashMap<String, Value>; - -impl Default for ValueKind { - fn default() -> Self { - ValueKind::Nil - } -} - -impl<T> From<Option<T>> for ValueKind - where T: Into<ValueKind> -{ - fn from(value: Option<T>) -> Self { - match value { - Some(value) => value.into(), - None => ValueKind::Nil, - } - } -} - -impl From<String> for ValueKind { - fn from(value: String) -> Self { - ValueKind::String(value.into()) - } -} - -impl<'a> From<&'a str> for ValueKind { - fn from(value: &'a str) -> Self { - ValueKind::String(value.into()) - } -} - -impl From<i64> for ValueKind { - fn from(value: i64) -> Self { - ValueKind::Integer(value) - } -} - -impl From<f64> for ValueKind { - fn from(value: f64) -> Self { - ValueKind::Float(value) - } -} - -impl From<bool> for ValueKind { - fn from(value: bool) -> Self { - ValueKind::Boolean(value) - } -} - -impl<T> From<HashMap<String, T>> for ValueKind - where T: Into<Value> -{ - fn from(values: HashMap<String, T>) -> Self { - let mut r = HashMap::new(); - - for (k, v) in values { - r.insert(k.clone(), v.into()); - } - - ValueKind::Table(r) - } -} - -impl<T> From<Vec<T>> for ValueKind - where T: Into<Value> -{ - fn from(values: Vec<T>) -> Self { - let mut l = Vec::new(); - - for v in values { - l.push(v.into()); - } - - ValueKind::Array(l) - } -} - -/// A configuration value. -#[derive(Default, Debug, Clone)] -pub struct Value { - /// A description of the original location of the value. - /// - /// A Value originating from a File might contain: - /// ``` - /// Settings.toml at line 1 column 2 - /// ``` - /// - /// A Value originating from the environment would contain: - /// ``` - /// the envrionment - /// ``` - /// - /// A Value originating from a remote source might contain: - /// ``` - /// etcd+http://127.0.0.1:2379 - /// ``` - origin: Option<String>, - - /// Underlying kind of the configuration value. - pub kind: ValueKind, -} - -impl Value { - pub fn new<V>(origin: Option<&String>, kind: V) -> Self - where V: Into<ValueKind> - { - Value { - origin: origin.cloned(), - kind: kind.into(), - } - } - - /// Returns `self` as a bool, if possible. - pub fn into_bool(self) -> Result<bool> { - match self.kind { - ValueKind::Boolean(value) => Ok(value), - ValueKind::Integer(value) => Ok(value != 0), - ValueKind::Float(value) => Ok(value != 0.0), - - ValueKind::String(ref value) => { - match value.to_lowercase().as_ref() { - "1" | "true" | "on" | "yes" => Ok(true), - "0" | "false" | "off" | "no" => Ok(false), - - // Unexpected string value - s @ _ => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Str(s.into()), "a boolean")), - } - } - - // Unexpected type - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "a boolean")), - ValueKind::Table(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "a boolean")), - ValueKind::Array(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "a boolean")), - } - } - - /// Returns `self` into an i64, if possible. - pub fn into_int(self) -> Result<i64> { - match self.kind { - ValueKind::Integer(value) => Ok(value), - - ValueKind::String(ref s) => s.parse().map_err(|_| { - // Unexpected string - ConfigError::invalid_type(self.origin.clone(), Unexpected::Str(s.clone()), "an integer") - }), - - ValueKind::Boolean(value) => Ok(if value { 1 } else { 0 }), - ValueKind::Float(value) => Ok(value.round() as i64), - - // Unexpected type - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "an integer")), - ValueKind::Table(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "an integer")), - ValueKind::Array(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "an integer")), - } - } - - /// Returns `self` into a f64, if possible. - pub fn into_float(self) -> Result<f64> { - match self.kind { - ValueKind::Float(value) => Ok(value), - - ValueKind::String(ref s) => s.parse().map_err(|_| { - // Unexpected string - ConfigError::invalid_type(self.origin.clone(), Unexpected::Str(s.clone()), "a floating point") - }), - - ValueKind::Integer(value) => Ok(value as f64), - ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }), - - // Unexpected type - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "a floating point")), - ValueKind::Table(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "a floating point")), - ValueKind::Array(_) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "a floating point")), - } - } - - /// Returns `self` into a str, if possible. - pub fn into_str(self) -> Result<String> { - match self.kind { - ValueKind::String(value) => Ok(value), - - // Cannot convert - ValueKind::Float(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "a string")), - ValueKind::Integer(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "a string")), - ValueKind::Boolean(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "a string")), - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a string")), - ValueKind::Table(_) => Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "a string")), - ValueKind::Array(_) => Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a string")), - } - } - - /// Returns `self` into an array, if possible - pub fn into_array(self) -> Result<Vec<Value>> { - match self.kind { - ValueKind::Array(value) => Ok(value), - - // Cannot convert - ValueKind::Float(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "an array")), - ValueKind::String(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "an array")), - ValueKind::Integer(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "an array")), - ValueKind::Boolean(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "an array")), - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "an array")), - ValueKind::Table(_) => Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "an array")), - } - } - - /// If the `Value` is a Table, returns the associated Map. - pub fn into_table(self) -> Result<HashMap<String, Value>> { - match self.kind { - ValueKind::Table(value) => Ok(value), - - // Cannot convert - ValueKind::Float(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "a map")), - ValueKind::String(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "a map")), - ValueKind::Integer(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "a map")), - ValueKind::Boolean(value) => Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "a map")), - ValueKind::Nil => Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a map")), - ValueKind::Array(_) => Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a map")), - } - } -} - -impl<T> From<T> for Value - where T: Into<ValueKind> -{ - fn from(value: T) -> Self { - Value { - origin: None, - kind: value.into(), - } - } -} diff --git a/lib/src/config.rs b/src/config.rs index 93d7fc0..4d24a1d 100644 --- a/lib/src/config.rs +++ b/src/config.rs @@ -81,6 +81,10 @@ impl Config { Ok(()) } + pub fn deserialize<T: Deserialize>(&self) -> Result<T> { + return T::deserialize(self.cache.clone()); + } + pub fn get<T: Deserialize>(&self, key: &str) -> Result<T> { // Parse the key into a path expression let expr: path::Expression = key.to_lowercase().parse()?; diff --git a/lib/src/de.rs b/src/de.rs index 89a3bcf..9a9ef58 100644 --- a/lib/src/de.rs +++ b/src/de.rs @@ -28,6 +28,78 @@ impl de::Deserializer for Value { } #[inline] + fn deserialize_bool<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_bool(self.into_bool()?) + } + + #[inline] + fn deserialize_i8<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_i8(self.into_int()? as i8) + } + + #[inline] + fn deserialize_i16<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_i16(self.into_int()? as i16) + } + + #[inline] + fn deserialize_i32<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_i32(self.into_int()? as i32) + } + + #[inline] + fn deserialize_i64<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_i64(self.into_int()?) + } + + #[inline] + fn deserialize_u8<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_u8(self.into_int()? as u8) + } + + #[inline] + fn deserialize_u16<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_u16(self.into_int()? as u16) + } + + #[inline] + fn deserialize_u32<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_u32(self.into_int()? as u32) + } + + #[inline] + fn deserialize_u64<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + // FIXME: This should *fail* if the value does not fit in the requets integer type + visitor.visit_u64(self.into_int()? as u64) + } + + #[inline] + fn deserialize_f32<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_f32(self.into_float()? as f32) + } + + #[inline] + fn deserialize_f64<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_f64(self.into_float()?) + } + + #[inline] + fn deserialize_str<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_string(self.into_str()?) + } + + #[inline] + fn deserialize_string<V: de::Visitor>(self, visitor: V) -> Result<V::Value> { + visitor.visit_string(self.into_str()?) + } + + #[inline] fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> where V: de::Visitor { @@ -39,7 +111,7 @@ impl de::Deserializer for Value { } forward_to_deserialize! { - bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + char seq seq_fixed_size bytes byte_buf map struct unit enum newtype_struct struct_field ignored_any unit_struct tuple_struct tuple } diff --git a/lib/src/error.rs b/src/error.rs index b97ebac..b97ebac 100644 --- a/lib/src/error.rs +++ b/src/error.rs diff --git a/lib/src/file/format/mod.rs b/src/file/format/mod.rs index 5c97a7f..5c97a7f 100644 --- a/lib/src/file/format/mod.rs +++ b/src/file/format/mod.rs diff --git a/lib/src/file/format/toml.rs b/src/file/format/toml.rs index bbe6aa6..bbe6aa6 100644 --- a/lib/src/file/format/toml.rs +++ b/src/file/format/toml.rs diff --git a/lib/src/file/mod.rs b/src/file/mod.rs index 7534ddb..7534ddb 100644 --- a/lib/src/file/mod.rs +++ b/src/file/mod.rs diff --git a/lib/src/file/source/file.rs b/src/file/source/file.rs index 124b7dd..124b7dd 100644 --- a/lib/src/file/source/file.rs +++ b/src/file/source/file.rs diff --git a/lib/src/file/source/mod.rs b/src/file/source/mod.rs index 4aeafa5..4aeafa5 100644 --- a/lib/src/file/source/mod.rs +++ b/src/file/source/mod.rs diff --git a/lib/src/file/source/string.rs b/src/file/source/string.rs index e1d9f64..e1d9f64 100644 --- a/lib/src/file/source/string.rs +++ b/src/file/source/string.rs diff --git a/lib/src/lib.rs b/src/lib.rs index 212e621..212e621 100644 --- a/lib/src/lib.rs +++ b/src/lib.rs diff --git a/lib/src/path/mod.rs b/src/path/mod.rs index 46e2290..f889283 100644 --- a/lib/src/path/mod.rs +++ b/src/path/mod.rs @@ -16,9 +16,7 @@ impl FromStr for Expression { type Err = ConfigError; fn from_str(s: &str) -> Result<Expression> { - parser::from_str(s.as_bytes()).to_result().map_err(|kind| { - ConfigError::PathParse(kind) - }) + parser::from_str(s).map_err(|kind| ConfigError::PathParse(kind)) } } diff --git a/lib/src/path/parser.rs b/src/path/parser.rs index ad7ab91..eea4343 100644 --- a/lib/src/path/parser.rs +++ b/src/path/parser.rs @@ -52,8 +52,8 @@ fn postfix(expr: Expression) -> Box<Fn(&[u8]) -> IResult<&[u8], Expression>> { }); } -pub fn from_str(input: &[u8]) -> IResult<&[u8], Expression> { - match ident(input) { +pub fn from_str(input: &str) -> Result<Expression, ErrorKind> { + match ident(input.as_bytes()) { IResult::Done(mut rem, mut expr) => { while rem.len() > 0 { match postfix(expr)(rem) { @@ -64,16 +64,16 @@ pub fn from_str(input: &[u8]) -> IResult<&[u8], Expression> { // Forward Incomplete and Error result @ _ => { - return result; + return result.to_result(); } } } - IResult::Done(&[], expr) + Ok(expr) } // Forward Incomplete and Error - result @ _ => result, + result @ _ => result.to_result(), } } diff --git a/lib/src/source.rs b/src/source.rs index 7519438..7519438 100644 --- a/lib/src/source.rs +++ b/src/source.rs diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..3f659bc --- /dev/null +++ b/src/value.rs @@ -0,0 +1,328 @@ +use std::collections::HashMap; +use std::fmt::Display; +use error::*; + +/// Underlying kind of the configuration value. +#[derive(Debug, Clone)] +pub enum ValueKind { + Nil, + Boolean(bool), + Integer(i64), + Float(f64), + String(String), + Table(Table), + Array(Array), +} + +pub type Array = Vec<Value>; +pub type Table = HashMap<String, Value>; + +impl Default for ValueKind { + fn default() -> Self { + ValueKind::Nil + } +} + +impl<T> From<Option<T>> for ValueKind + where T: Into<ValueKind> +{ + fn from(value: Option<T>) -> Self { + match value { + Some(value) => value.into(), + None => ValueKind::Nil, + } + } +} + +impl From<String> for ValueKind { + fn from(value: String) -> Self { + ValueKind::String(value.into()) + } +} + +impl<'a> From<&'a str> for ValueKind { + fn from(value: &'a str) -> Self { + ValueKind::String(value.into()) + } +} + +impl From<i64> for ValueKind { + fn from(value: i64) -> Self { + ValueKind::Integer(value) + } +} + +impl From<f64> for ValueKind { + fn from(value: f64) -> Self { + ValueKind::Float(value) + } +} + +impl From<bool> for ValueKind { + fn from(value: bool) -> Self { + ValueKind::Boolean(value) + } +} + +impl<T> From<HashMap<String, T>> for ValueKind + where T: Into<Value> +{ + fn from(values: HashMap<String, T>) -> Self { + let mut r = HashMap::new(); + + for (k, v) in values { + r.insert(k.clone(), v.into()); + } + + ValueKind::Table(r) + } +} + +impl<T> From<Vec<T>> for ValueKind + where T: Into<Value> +{ + fn from(values: Vec<T>) -> Self { + let mut l = Vec::new(); + + for v in values { + l.push(v.into()); + } + + ValueKind::Array(l) + } +} + +/// A configuration value. +#[derive(Default, Debug, Clone)] +pub struct Value { + /// A description of the original location of the value. + /// + /// A Value originating from a File might contain: + /// ``` + /// Settings.toml at line 1 column 2 + /// ``` + /// + /// A Value |