summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Leckey <ryan@launchbadge.com>2017-06-01 23:22:04 -0700
committerRyan Leckey <ryan@launchbadge.com>2017-06-01 23:22:04 -0700
commitbfc44c331a77d8c341c076e72df5ed0b56fbd422 (patch)
treec757723957be6b880d1e0d8d26ae2b1c9c606ed2
parent4357840e95f3646494ddeea4aae12425dfab2db8 (diff)
Move things around and get some tests in place
-rw-r--r--Cargo.toml34
-rw-r--r--examples/basic/Cargo.toml7
-rw-r--r--examples/basic/src/main.rs35
-rw-r--r--examples/file-json/Cargo.toml7
-rw-r--r--examples/file-json/Settings.json5
-rw-r--r--examples/file-json/src/main.rs12
-rw-r--r--examples/file-toml/Cargo.toml9
-rw-r--r--examples/file-toml/Settings.toml4
-rw-r--r--examples/file-toml/src/main.rs22
-rw-r--r--examples/file-yaml/Cargo.toml7
-rw-r--r--examples/file-yaml/Settings.yaml3
-rw-r--r--examples/file-yaml/src/main.rs12
-rw-r--r--lib/Cargo.toml24
-rw-r--r--lib/src/value.rs249
-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.rs328
-rw-r--r--tests/Settings.toml12
-rw-r--r--tests/scalar.rs44
-rw-r--r--tests/struct.rs68
31 files changed, 561 insertions, 413 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 99ff591..b238ca6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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