From 7d870758cbd9ad4181471ad40184d1bac1204e1e Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Sat, 28 Jan 2017 20:46:29 -0800 Subject: Use 'Cow' to remove unnecessary allocations --- src/value.rs | 86 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) (limited to 'src/value.rs') diff --git a/src/value.rs b/src/value.rs index a887104..ad173e8 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,49 +1,53 @@ use std::convert::From; use std::collections::HashMap; +use std::borrow::Cow; /// A configuration value. /// /// Has an underlying or native type that comes from the configuration source /// but will be coerced into the requested type. #[derive(Debug, Clone)] -pub enum Value { - String(String), +pub enum Value<'a> { + String(Cow<'a, str>), Integer(i64), Float(f64), Boolean(bool), - Table(HashMap), - Array(Vec), + Table(HashMap>), + Array(Vec>), } -impl Value { - /// Gets the underyling value as a string, performing a conversion only if neccessary. - pub fn as_str(self) -> Option { - if let Value::String(value) = self { - Some(value) - } else if let Value::Integer(value) = self { - Some(value.to_string()) - } else if let Value::Float(value) = self { - Some(value.to_string()) - } else if let Value::Boolean(value) = self { - Some(value.to_string()) +impl<'a> Value<'a> { + /// Gets the underlying value as a string, performing a conversion only if neccessary. + pub fn as_str(&'a self) -> Option> { + if let Value::String(ref value) = *self { + Some(match *value { + Cow::Borrowed(v) => Cow::Borrowed(v), + Cow::Owned(ref v) => Cow::Borrowed(v), + }) + } 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 { - if let Value::Boolean(value) = self { + pub fn as_bool(&self) -> Option { + if let Value::Boolean(value) = *self { Some(value) - } else if let Value::String(ref value) = self { + } else if let Value::String(ref value) = *self { match value.to_lowercase().as_ref() { "1" | "true" | "on" | "yes" => Some(true), "0" | "false" | "off" | "no" => Some(false), _ => None, } - } else if let Value::Integer(value) = self { + } else if let Value::Integer(value) = *self { Some(value != 0) - } else if let Value::Float(value) = self { + } else if let Value::Float(value) = *self { Some(value != 0.0) } else { None @@ -51,14 +55,14 @@ impl Value { } /// Gets the underlying type as an integer, performing a conversion only if neccessary. - pub fn as_int(self) -> Option { - if let Value::Integer(value) = self { + pub fn as_int(&self) -> Option { + if let Value::Integer(value) = *self { Some(value) - } else if let Value::String(ref value) = self { + } else if let Value::String(ref value) = *self { value.parse().ok() - } else if let Value::Boolean(value) = self { + } else if let Value::Boolean(value) = *self { Some(if value { 1 } else { 0 }) - } else if let Value::Float(value) = self { + } else if let Value::Float(value) = *self { Some(value.round() as i64) } else { None @@ -66,14 +70,14 @@ impl Value { } /// Gets the underlying type as a floating-point, performing a conversion only if neccessary. - pub fn as_float(self) -> Option { - if let Value::Float(value) = self { + pub fn as_float(&self) -> Option { + if let Value::Float(value) = *self { Some(value) - } else if let Value::String(ref value) = self { + } else if let Value::String(ref value) = *self { value.parse().ok() - } else if let Value::Integer(value) = self { + } else if let Value::Integer(value) = *self { Some(value as f64) - } else if let Value::Boolean(value) = self { + } else if let Value::Boolean(value) = *self { Some(if value { 1.0 } else { 0.0 }) } else { None @@ -84,32 +88,32 @@ impl Value { // Generalized construction from type into variant is needed // for setting configuration values -impl From for Value { - fn from(value: String) -> Value { - Value::String(value) +impl<'a> From for Value<'a> { + fn from(value: String) -> Value<'a> { + Value::String(value.into()) } } -impl<'a> From<&'a str> for Value { - fn from(value: &'a str) -> Value { +impl<'a> From<&'a str> for Value<'a> { + fn from(value: &'a str) -> Value<'a> { Value::String(value.into()) } } -impl From for Value { - fn from(value: i64) -> Value { +impl<'a> From for Value<'a> { + fn from(value: i64) -> Value<'a> { Value::Integer(value) } } -impl From for Value { - fn from(value: f64) -> Value { +impl<'a> From for Value<'a> { + fn from(value: f64) -> Value<'a> { Value::Float(value) } } -impl From for Value { - fn from(value: bool) -> Value { +impl<'a> From for Value<'a> { + fn from(value: bool) -> Value<'a> { Value::Boolean(value) } } -- cgit v1.2.3