summaryrefslogtreecommitdiffstats
path: root/src/value.rs
diff options
context:
space:
mode:
authorRyan Leckey <leckey.ryan@gmail.com>2017-01-25 18:07:12 -0800
committerRyan Leckey <leckey.ryan@gmail.com>2017-01-25 18:07:12 -0800
commit91f72c5c2a20c5a9b6b17b5d9ee626645783e5db (patch)
treec420add20f11d7cee3a1dadee060b4e1cd3fe017 /src/value.rs
parent286703d802a433b78ebb334f864136b942f86b5c (diff)
Big cleanup of the Value API
Diffstat (limited to 'src/value.rs')
-rw-r--r--src/value.rs189
1 files changed, 78 insertions, 111 deletions
diff --git a/src/value.rs b/src/value.rs
index 295c7c0..a2b037c 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -1,16 +1,84 @@
-use std::convert::{From, TryFrom};
+use std::convert::From;
+use std::borrow::Cow;
// Variant for a configuration Value
-// The additional Option<String> is used for the textual representation of the
-// underlying type (to cache the string generation) but only if requested.
+#[derive(Clone)]
pub enum Value {
String(String),
- Integer(i64, Option<String>),
- Float(f64, Option<String>),
- Boolean(bool, Option<String>),
+ Integer(i64),
+ Float(f64),
+ Boolean(bool),
}
-// Conversion from type into variant
+impl Value {
+ /// Gets the underyling value as a string, performing a conversion only if neccessary.
+ #[allow(needless_lifetimes)]
+ pub fn as_str<'a>(&'a self) -> Option<Cow<'a, str>> {
+ if let Value::String(ref value) = *self {
+ Some(Cow::Borrowed(value))
+ } else if let Value::Integer(value) = *self {
+ Some(Cow::Owned(value.to_string()))
+ } else if let Value::Float(value) = *self {
+ Some(Cow::Owned(value.to_string()))
+ } else if let Value::Boolean(value) = *self {
+ Some(Cow::Owned(value.to_string()))
+ } else {
+ None
+ }
+ }
+
+ /// Gets the underlying type as a boolean, performing a conversion only if neccessary.
+ pub fn as_bool(&self) -> Option<bool> {
+ if let Value::Boolean(value) = *self {
+ Some(value)
+ } else if let Value::String(ref value) = *self {
+ Some(match value.to_lowercase().as_ref() {
+ "1" | "true" | "on" | "yes" => true,
+ _ => false,
+ })
+ } else if let Value::Integer(value) = *self {
+ Some(value != 0)
+ } else if let Value::Float(value) = *self {
+ Some(value != 0.0)
+ } else {
+ None
+ }
+ }
+
+ /// Gets the underlying type as an integer, performing a conversion only if neccessary.
+ pub fn as_int(&self) -> Option<i64> {
+ if let Value::Integer(value) = *self {
+ Some(value)
+ } else if let Value::String(ref value) = *self {
+ value.parse().ok()
+ } else if let Value::Boolean(value) = *self {
+ Some(if value { 1 } else { 0 })
+ } else if let Value::Float(value) = *self {
+ Some(value.round() as i64)
+ } else {
+ None
+ }
+ }
+
+ /// Gets the underlying type as a floating-point, performing a conversion only if neccessary.
+ pub fn as_float(&self) -> Option<f64> {
+ if let Value::Float(value) = *self {
+ Some(value)
+ } else if let Value::String(ref value) = *self {
+ value.parse().ok()
+ } else if let Value::Integer(value) = *self {
+ Some(value as f64)
+ } else if let Value::Boolean(value) = *self {
+ Some(if value { 1.0 } else { 0.0 })
+ } else {
+ None
+ }
+ }
+}
+
+// Generalized construction from type into variant is needed
+// for setting configuration values
+
impl From<String> for Value {
fn from(value: String) -> Value {
Value::String(value)
@@ -25,119 +93,18 @@ impl<'a> From<&'a str> for Value {
impl From<i64> for Value {
fn from(value: i64) -> Value {
- Value::Integer(value, None)
+ Value::Integer(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Value {
- Value::Float(value, None)
+ Value::Float(value)
}
}
impl From<bool> for Value {
fn from(value: bool) -> Value {
- Value::Boolean(value, None)
- }
-}
-
-// Conversion from variant into type
-impl<'a> TryFrom<&'a mut Value> for &'a str {
- type Err = ();
-
- fn try_from(value: &mut Value) -> Result<&str, ()> {
- // When converting a non-string value into a string;
- // cache the conversion and return a reference
-
- if let Value::String(ref value) = *value {
- Ok(value)
- } else if let Value::Integer(value, ref mut text) = *value {
- if let Some(ref text) = *text {
- Ok(text)
- } else {
- *text = Some(value.to_string());
-
- Ok(text.as_ref().unwrap())
- }
- } else if let Value::Float(value, ref mut text) = *value {
- if let Some(ref text) = *text {
- Ok(text)
- } else {
- *text = Some(value.to_string());
-
- Ok(text.as_ref().unwrap())
- }
- } else if let Value::Boolean(value, ref mut text) = *value {
- if let Some(ref text) = *text {
- Ok(text)
- } else {
- *text = Some(value.to_string());
-
- Ok(text.as_ref().unwrap())
- }
- } else {
- Err(())
- }
- }
-}
-
-impl<'a> TryFrom<&'a mut Value> for i64 {
- type Err = ();
-
- fn try_from(value: &mut Value) -> Result<i64, ()> {
- if let Value::Integer(value, ..) = *value {
- Ok(value)
- } else if let Value::String(ref value) = *value {
- value.parse().map_err(|_| {
- // Drop specific error
- })
- } else if let Value::Boolean(value, ..) = *value {
- Ok(if value { 1 } else { 0 })
- } else if let Value::Float(value, ..) = *value {
- Ok(value.round() as i64)
- } else {
- Err(())
- }
- }
-}
-
-impl<'a> TryFrom<&'a mut Value> for f64 {
- type Err = ();
-
- fn try_from(value: &mut Value) -> Result<f64, ()> {
- if let Value::Float(value, ..) = *value {
- Ok(value)
- } else if let Value::String(ref value) = *value {
- value.parse().map_err(|_| {
- // Drop specific error
- })
- } else if let Value::Integer(value, ..) = *value {
- Ok(value as f64)
- } else if let Value::Boolean(value, ..) = *value {
- Ok(if value { 1.0 } else { 0.0 })
- } else {
- Err(())
- }
- }
-}
-
-impl<'a> TryFrom<&'a mut Value> for bool {
- type Err = ();
-
- fn try_from(value: &mut Value) -> Result<bool, ()> {
- if let Value::Boolean(value, ..) = *value {
- Ok(value)
- } else if let Value::String(ref value) = *value {
- Ok(match value.to_lowercase().as_ref() {
- "1" | "true" | "on" | "yes" => true,
- _ => false,
- })
- } else if let Value::Integer(value, ..) = *value {
- Ok(value != 0)
- } else if let Value::Float(value, ..) = *value {
- Ok(value != 0.0)
- } else {
- Err(())
- }
+ Value::Boolean(value)
}
}