From 116b860bc40e283518243139fe54ac5a0be8c6d6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 14 Mar 2021 10:29:39 +0100 Subject: Add support for different sized integers This also enables support for 128 bit integers. Nothing is tested, though. Signed-off-by: Matthias Beyer --- src/de.rs | 12 +++- src/error.rs | 12 +++- src/file/format/hjson.rs | 5 +- src/file/format/json.rs | 2 +- src/file/format/yaml.rs | 2 +- src/value.rs | 175 +++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 186 insertions(+), 22 deletions(-) diff --git a/src/de.rs b/src/de.rs index c4fdeb2..8f0c619 100644 --- a/src/de.rs +++ b/src/de.rs @@ -16,7 +16,11 @@ impl<'de> de::Deserializer<'de> for Value { // Deserialize based on the underlying type match self.kind { ValueKind::Nil => visitor.visit_unit(), - ValueKind::Integer(i) => visitor.visit_i64(i), + ValueKind::I8(i) => visitor.visit_i8(i), + ValueKind::I16(i) => visitor.visit_i16(i), + ValueKind::I32(i) => visitor.visit_i32(i), + ValueKind::I64(i) => visitor.visit_i64(i), + ValueKind::I128(i) => visitor.visit_i128(i), ValueKind::Boolean(b) => visitor.visit_bool(b), ValueKind::Float(f) => visitor.visit_f64(f), ValueKind::String(s) => visitor.visit_string(s), @@ -348,7 +352,11 @@ impl<'de> de::Deserializer<'de> for Config { // Deserialize based on the underlying type match self.cache.kind { ValueKind::Nil => visitor.visit_unit(), - ValueKind::Integer(i) => visitor.visit_i64(i), + ValueKind::I8(i) => visitor.visit_i8(i), + ValueKind::I16(i) => visitor.visit_i16(i), + ValueKind::I32(i) => visitor.visit_i32(i), + ValueKind::I64(i) => visitor.visit_i64(i), + ValueKind::I128(i) => visitor.visit_i128(i), ValueKind::Boolean(b) => visitor.visit_bool(b), ValueKind::Float(f) => visitor.visit_f64(f), ValueKind::String(s) => visitor.visit_string(s), diff --git a/src/error.rs b/src/error.rs index deb79ee..0972c6a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,7 +9,11 @@ use std::result; #[derive(Debug)] pub enum Unexpected { Bool(bool), - Integer(i64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), Float(f64), Str(String), Unit, @@ -21,7 +25,11 @@ impl fmt::Display for Unexpected { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { match *self { Unexpected::Bool(b) => write!(f, "boolean `{}`", b), - Unexpected::Integer(i) => write!(f, "integer `{}`", i), + Unexpected::I8(i) => write!(f, "integer 8 bit `{}`", i), + Unexpected::I16(i) => write!(f, "integer 16 bit `{}`", i), + Unexpected::I32(i) => write!(f, "integer 32 bit `{}`", i), + Unexpected::I64(i) => write!(f, "integer 64 bit `{}`", i), + Unexpected::I128(i) => write!(f, "integer 128 bit `{}`", i), Unexpected::Float(v) => write!(f, "floating point `{}`", v), Unexpected::Str(ref s) => write!(f, "string {:?}", s), Unexpected::Unit => write!(f, "unit value"), diff --git a/src/file/format/hjson.rs b/src/file/format/hjson.rs index 457cfbf..ed8d915 100644 --- a/src/file/format/hjson.rs +++ b/src/file/format/hjson.rs @@ -22,9 +22,10 @@ fn from_hjson_value(uri: Option<&String>, value: &serde_hjson::Value) -> Value { match *value { serde_hjson::Value::String(ref value) => Value::new(uri, ValueKind::String(value.clone())), - serde_hjson::Value::I64(value) => Value::new(uri, ValueKind::Integer(value)), + serde_hjson::Value::I64(value) => Value::new(uri, ValueKind::I64(value)), - serde_hjson::Value::U64(value) => Value::new(uri, ValueKind::Integer(value as i64)), + // FIXME this is bad + serde_hjson::Value::U64(value) => Value::new(uri, ValueKind::I64(value as i64)), serde_hjson::Value::F64(value) => Value::new(uri, ValueKind::Float(value)), diff --git a/src/file/format/json.rs b/src/file/format/json.rs index 0ff2beb..759e1f8 100644 --- a/src/file/format/json.rs +++ b/src/file/format/json.rs @@ -24,7 +24,7 @@ fn from_json_value(uri: Option<&String>, value: &serde_json::Value) -> Value { serde_json::Value::Number(ref value) => { if let Some(value) = value.as_i64() { - Value::new(uri, ValueKind::Integer(value)) + Value::new(uri, ValueKind::I64(value)) } else if let Some(value) = value.as_f64() { Value::new(uri, ValueKind::Float(value)) } else { diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs index c458c3c..c7c9be4 100644 --- a/src/file/format/yaml.rs +++ b/src/file/format/yaml.rs @@ -36,7 +36,7 @@ fn from_yaml_value(uri: Option<&String>, value: &yaml::Yaml) -> Value { // TODO: Figure out in what cases this can panic? Value::new(uri, ValueKind::Float(value.parse::().unwrap())) } - yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::Integer(value)), + yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::I64(value)), yaml::Yaml::Boolean(value) => Value::new(uri, ValueKind::Boolean(value)), yaml::Yaml::Hash(ref table) => { let mut m = HashMap::new(); diff --git a/src/value.rs b/src/value.rs index 700279b..c02da73 100644 --- a/src/value.rs +++ b/src/value.rs @@ -9,7 +9,11 @@ use std::fmt::Display; pub enum ValueKind { Nil, Boolean(bool), - Integer(i64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), Float(f64), String(String), Table(Table), @@ -49,9 +53,33 @@ impl<'a> From<&'a str> for ValueKind { } } +impl From for ValueKind { + fn from(value: i8) -> Self { + ValueKind::I8(value) + } +} + +impl From for ValueKind { + fn from(value: i16) -> Self { + ValueKind::I16(value) + } +} + +impl From for ValueKind { + fn from(value: i32) -> Self { + ValueKind::I32(value) + } +} + impl From for ValueKind { fn from(value: i64) -> Self { - ValueKind::Integer(value) + ValueKind::I64(value) + } +} + +impl From for ValueKind { + fn from(value: i128) -> Self { + ValueKind::I128(value) } } @@ -102,7 +130,11 @@ impl Display for ValueKind { match *self { ValueKind::String(ref value) => write!(f, "{}", value), ValueKind::Boolean(value) => write!(f, "{}", value), - ValueKind::Integer(value) => write!(f, "{}", value), + ValueKind::I8(value) => write!(f, "{}", value), + ValueKind::I16(value) => write!(f, "{}", value), + ValueKind::I32(value) => write!(f, "{}", value), + ValueKind::I64(value) => write!(f, "{}", value), + ValueKind::I128(value) => write!(f, "{}", value), ValueKind::Float(value) => write!(f, "{}", value), ValueKind::Nil => write!(f, "nil"), @@ -160,7 +192,11 @@ impl Value { pub fn into_bool(self) -> Result { match self.kind { ValueKind::Boolean(value) => Ok(value), - ValueKind::Integer(value) => Ok(value != 0), + ValueKind::I8(value) => Ok(value != 0), + ValueKind::I16(value) => Ok(value != 0), + ValueKind::I32(value) => Ok(value != 0), + ValueKind::I64(value) => Ok(value != 0), + ValueKind::I128(value) => Ok(value != 0), ValueKind::Float(value) => Ok(value != 0.0), ValueKind::String(ref value) => { @@ -200,7 +236,11 @@ impl Value { // FIXME: Should this not be `try_deserialize_*` ? pub fn into_int(self) -> Result { match self.kind { - ValueKind::Integer(value) => Ok(value), + ValueKind::I8(value) => Ok(value as i64), + ValueKind::I16(value) => Ok(value as i64), + ValueKind::I32(value) => Ok(value as i64), + ValueKind::I64(value) => Ok(value), + ValueKind::I128(value) => Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::I128(value), "an 64 bit or less integer")), ValueKind::String(ref s) => { match s.to_lowercase().as_ref() { @@ -241,6 +281,54 @@ impl Value { } } + /// Returns `self` into an i128, if possible. + pub fn into_int128(self) -> Result { + match self.kind { + ValueKind::I8(value) => Ok(value as i128), + ValueKind::I16(value) => Ok(value as i128), + ValueKind::I32(value) => Ok(value as i128), + ValueKind::I64(value) => Ok(value as i128), + ValueKind::I128(value) => Ok(value), + + ValueKind::String(ref s) => { + match s.to_lowercase().as_ref() { + "true" | "on" | "yes" => Ok(1), + "false" | "off" | "no" => Ok(0), + _ => { + 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 i128), + + // Unexpected type + ValueKind::Nil => Err(ConfigError::invalid_type( + self.origin, + Unexpected::Unit, + "an integer", + )), + ValueKind::Table(_) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::Map, + "an integer", + )), + ValueKind::Array(_) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::Seq, + "an integer", + )), + } + } + /// Returns `self` into a f64, if possible. // FIXME: Should this not be `try_deserialize_*` ? pub fn into_float(self) -> Result { @@ -264,7 +352,11 @@ impl Value { } } - ValueKind::Integer(value) => Ok(value as f64), + ValueKind::I8(value) => Ok(value as f64), + ValueKind::I16(value) => Ok(value as f64), + ValueKind::I32(value) => Ok(value as f64), + ValueKind::I64(value) => Ok(value as f64), + ValueKind::I128(value) => Ok(value as f64), ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }), // Unexpected type @@ -293,7 +385,11 @@ impl Value { ValueKind::String(value) => Ok(value), ValueKind::Boolean(value) => Ok(value.to_string()), - ValueKind::Integer(value) => Ok(value.to_string()), + ValueKind::I8(value) => Ok(value.to_string()), + ValueKind::I16(value) => Ok(value.to_string()), + ValueKind::I32(value) => Ok(value.to_string()), + ValueKind::I64(value) => Ok(value.to_string()), + ValueKind::I128(value) => Ok(value.to_string()), ValueKind::Float(value) => Ok(value.to_string()), // Cannot convert @@ -332,9 +428,29 @@ impl Value { Unexpected::Str(value), "an array", )), - ValueKind::Integer(value) => Err(ConfigError::invalid_type( + ValueKind::I8(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I8(value), + "an array", + )), + ValueKind::I16(value) => Err(ConfigError::invalid_type( self.origin, - Unexpected::Integer(value), + Unexpected::I16(value), + "an array", + )), + ValueKind::I32(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I32(value), + "an array", + )), + ValueKind::I64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I64(value), + "an array", + )), + ValueKind::I128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I128(value), "an array", )), ValueKind::Boolean(value) => Err(ConfigError::invalid_type( @@ -372,9 +488,29 @@ impl Value { Unexpected::Str(value), "a map", )), - ValueKind::Integer(value) => Err(ConfigError::invalid_type( + ValueKind::I8(value) => Err(ConfigError::invalid_type( self.origin, - Unexpected::Integer(value), + Unexpected::I8(value), + "a map", + )), + ValueKind::I16(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I16(value), + "a map", + )), + ValueKind::I32(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I32(value), + "a map", + )), + ValueKind::I64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I64(value), + "a map", + )), + ValueKind::I128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I128(value), "a map", )), ValueKind::Boolean(value) => Err(ConfigError::invalid_type( @@ -418,17 +554,17 @@ impl<'de> Deserialize<'de> for Value { #[inline] fn visit_i8(self, value: i8) -> ::std::result::Result { - Ok((value as i64).into()) + Ok((value).into()) } #[inline] fn visit_i16(self, value: i16) -> ::std::result::Result { - Ok((value as i64).into()) + Ok((value).into()) } #[inline] fn visit_i32(self, value: i32) -> ::std::result::Result { - Ok((value as i64).into()) + Ok((value).into()) } #[inline] @@ -436,6 +572,11 @@ impl<'de> Deserialize<'de> for Value { Ok(value.into()) } + #[inline] + fn visit_i128(self, value: i128) -> ::std::result::Result { + Ok(value.into()) + } + #[inline] fn visit_u8(self, value: u8) -> ::std::result::Result { Ok((value as i64).into()) @@ -457,6 +598,12 @@ impl<'de> Deserialize<'de> for Value { Ok((value as i64).into()) } + #[inline] + fn visit_u128(self, value: u128) -> ::std::result::Result { + // FIXME: This is bad + Ok((value as i128).into()) + } + #[inline] fn visit_f64(self, value: f64) -> ::std::result::Result { Ok(value.into()) -- cgit v1.2.3