summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-03-14 10:29:39 +0100
committerMatthias Beyer <mail@beyermatthias.de>2021-11-21 12:20:18 +0100
commitf4424668191d1ae421127770eda1ad894dd01802 (patch)
treedc3e184343acf2c40ae1daae2c7f9ef94ef342a8
parente8cc94aaf6d44ad69cafe75d9a4a3944959103fe (diff)
Add support for different sized integers
This also enables support for 128 bit integers. Nothing is tested, though. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--src/de.rs12
-rw-r--r--src/env.rs2
-rw-r--r--src/error.rs12
-rw-r--r--src/file/format/json.rs2
-rw-r--r--src/file/format/json5.rs4
-rw-r--r--src/file/format/ron.rs2
-rw-r--r--src/file/format/yaml.rs2
-rw-r--r--src/value.rs179
8 files changed, 191 insertions, 24 deletions
diff --git a/src/de.rs b/src/de.rs
index 60fa4ea..8f55565 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -19,7 +19,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),
@@ -345,7 +349,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/env.rs b/src/env.rs
index a349dd6..d0e8d54 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -111,7 +111,7 @@ impl Source for Environment {
if let Ok(parsed) = value.to_lowercase().parse::<bool>() {
ValueKind::Boolean(parsed)
} else if let Ok(parsed) = value.parse::<i64>() {
- ValueKind::Integer(parsed)
+ ValueKind::I64(parsed)
} else if let Ok(parsed) = value.parse::<f64>() {
ValueKind::Float(parsed)
} else {
diff --git a/src/error.rs b/src/error.rs
index 9778649..6751e05 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -8,7 +8,11 @@ use serde::ser;
#[derive(Debug)]
pub enum Unexpected {
Bool(bool),
- Integer(i64),
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ I128(i128),
Float(f64),
Str(String),
Unit,
@@ -20,7 +24,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/json.rs b/src/file/format/json.rs
index e3d8b87..1720cb6 100644
--- a/src/file/format/json.rs
+++ b/src/file/format/json.rs
@@ -23,7 +23,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/json5.rs b/src/file/format/json5.rs
index c156797..8f9f605 100644
--- a/src/file/format/json5.rs
+++ b/src/file/format/json5.rs
@@ -22,7 +22,7 @@ pub fn parse(
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
match json5_rs::from_str::<Val>(text)? {
Val::String(ref value) => Err(Unexpected::Str(value.clone())),
- Val::Integer(value) => Err(Unexpected::Integer(value)),
+ Val::Integer(value) => Err(Unexpected::I64(value)),
Val::Float(value) => Err(Unexpected::Float(value)),
Val::Boolean(value) => Err(Unexpected::Bool(value)),
Val::Array(_) => Err(Unexpected::Seq),
@@ -40,7 +40,7 @@ fn from_json5_value(uri: Option<&String>, value: Val) -> Value {
let vk = match value {
Val::Null => ValueKind::Nil,
Val::String(v) => ValueKind::String(v),
- Val::Integer(v) => ValueKind::Integer(v),
+ Val::Integer(v) => ValueKind::I64(v),
Val::Float(v) => ValueKind::Float(v),
Val::Boolean(v) => ValueKind::Boolean(v),
Val::Object(table) => {
diff --git a/src/file/format/ron.rs b/src/file/format/ron.rs
index 3fb2a0f..fb2b063 100644
--- a/src/file/format/ron.rs
+++ b/src/file/format/ron.rs
@@ -31,7 +31,7 @@ fn from_ron_value(
ron::Value::Number(value) => match value {
ron::Number::Float(value) => ValueKind::Float(value.get()),
- ron::Number::Integer(value) => ValueKind::Integer(value),
+ ron::Number::Integer(value) => ValueKind::I64(value),
},
ron::Value::Char(value) => ValueKind::String(value.to_string()),
diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs
index de67efe..2a76261 100644
--- a/src/file/format/yaml.rs
+++ b/src/file/format/yaml.rs
@@ -46,7 +46,7 @@ fn from_yaml_value(
.map(ValueKind::Float)
.map(|f| Value::new(uri, f))
}
- yaml::Yaml::Integer(value) => Ok(Value::new(uri, ValueKind::Integer(value))),
+ yaml::Yaml::Integer(value) => Ok(Value::new(uri, ValueKind::I64(value))),
yaml::Yaml::Boolean(value) => Ok(Value::new(uri, ValueKind::Boolean(value))),
yaml::Yaml::Hash(ref table) => {
let mut m = Map::new();
diff --git a/src/value.rs b/src/value.rs
index 1523c1e..8569546 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -15,7 +15,11 @@ use crate::map::Map;
pub enum ValueKind {
Nil,
Boolean(bool),
- Integer(i64),
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ I128(i128),
Float(f64),
String(String),
Table(Table),
@@ -55,9 +59,33 @@ impl<'a> From<&'a str> for ValueKind {
}
}
+impl From<i8> for ValueKind {
+ fn from(value: i8) -> Self {
+ ValueKind::I8(value)
+ }
+}
+
+impl From<i16> for ValueKind {
+ fn from(value: i16) -> Self {
+ ValueKind::I16(value)
+ }
+}
+
+impl From<i32> for ValueKind {
+ fn from(value: i32) -> Self {
+ ValueKind::I32(value)
+ }
+}
+
impl From<i64> for ValueKind {
fn from(value: i64) -> Self {
- ValueKind::Integer(value)
+ ValueKind::I64(value)
+ }
+}
+
+impl From<i128> for ValueKind {
+ fn from(value: i128) -> Self {
+ ValueKind::I128(value)
}
}
@@ -97,7 +125,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"),
ValueKind::Table(ref table) => write!(f, "{{ {} }}", {
@@ -160,7 +192,11 @@ impl Value {
pub fn into_bool(self) -> Result<bool> {
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,15 @@ impl Value {
// FIXME: Should this not be `try_into_*` ?
pub fn into_int(self) -> Result<i64> {
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,
+ Unexpected::I128(value),
+ "an 64 bit or less integer",
+ )),
ValueKind::String(ref s) => {
match s.to_lowercase().as_ref() {
@@ -241,6 +285,54 @@ impl Value {
}
}
+ /// Returns `self` into an i128, if possible.
+ pub fn into_int128(self) -> Result<i128> {
+ 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_into_*` ?
pub fn into_float(self) -> Result<f64> {
@@ -264,7 +356,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 +389,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 +432,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::I16(value),
+ "an array",
+ )),
+ ValueKind::I32(value) => Err(ConfigError::invalid_type(
self.origin,
- Unexpected::Integer(value),
+ 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 +492,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::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::Integer(value),
+ Unexpected::I128(value),
"a map",
)),
ValueKind::Boolean(value) => Err(ConfigError::invalid_type(
@@ -418,17 +558,17 @@ impl<'de> Deserialize<'de> for Value {
#[inline]
fn visit_i8<E>(self, value: i8) -> ::std::result::Result<Value, E> {
- Ok((value as i64).into())
+ Ok((value).into())
}
#[inline]
fn visit_i16<E>(self, value: i16) -> ::std::result::Result<Value, E> {
- Ok((value as i64).into())
+ Ok((value).into())
}
#[inline]
fn visit_i32<E>(self, value: i32) -> ::std::result::Result<Value, E> {
- Ok((value as i64).into())
+ Ok((value).into())
}
#[inline]
@@ -437,6 +577,11 @@ impl<'de> Deserialize<'de> for Value {
}
#[inline]
+ fn visit_i128<E>(self, value: i128) -> ::std::result::Result<Value, E> {
+ Ok(value.into())
+ }
+
+ #[inline]
fn visit_u8<E>(self, value: u8) -> ::std::result::Result<Value, E> {
Ok((value as i64).into())
}
@@ -458,6 +603,12 @@ impl<'de> Deserialize<'de> for Value {
}
#[inline]
+ fn visit_u128<E>(self, value: u128) -> ::std::result::Result<Value, E> {
+ // FIXME: This is bad
+ Ok((value as i128).into())
+ }
+
+ #[inline]
fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Value, E> {
Ok(value.into())
}