diff options
author | Ryan Leckey <leckey.ryan@gmail.com> | 2017-01-25 18:07:12 -0800 |
---|---|---|
committer | Ryan Leckey <leckey.ryan@gmail.com> | 2017-01-25 18:07:12 -0800 |
commit | 91f72c5c2a20c5a9b6b17b5d9ee626645783e5db (patch) | |
tree | c420add20f11d7cee3a1dadee060b4e1cd3fe017 /src/value.rs | |
parent | 286703d802a433b78ebb334f864136b942f86b5c (diff) |
Big cleanup of the Value API
Diffstat (limited to 'src/value.rs')
-rw-r--r-- | src/value.rs | 189 |
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) } } |