diff --git a/src/de.rs b/src/de.rs index 3edac778..45429fce 100644 --- a/src/de.rs +++ b/src/de.rs @@ -18,6 +18,8 @@ impl<'de> de::Deserializer<'de> for Value { ValueKind::Nil => visitor.visit_unit(), ValueKind::I64(i) => visitor.visit_i64(i), ValueKind::I128(i) => visitor.visit_i128(i), + ValueKind::U64(i) => visitor.visit_u64(i), + ValueKind::U128(i) => visitor.visit_u128(i), ValueKind::Boolean(b) => visitor.visit_bool(b), ValueKind::Float(f) => visitor.visit_f64(f), ValueKind::String(s) => visitor.visit_string(s), @@ -351,6 +353,8 @@ impl<'de> de::Deserializer<'de> for Config { ValueKind::Nil => visitor.visit_unit(), ValueKind::I64(i) => visitor.visit_i64(i), ValueKind::I128(i) => visitor.visit_i128(i), + ValueKind::U64(i) => visitor.visit_u64(i), + ValueKind::U128(i) => visitor.visit_u128(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 01d3bd19..db00877a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,6 +11,8 @@ pub enum Unexpected { Bool(bool), I64(i64), I128(i128), + U64(u64), + U128(u128), Float(f64), Str(String), Unit, @@ -24,6 +26,8 @@ impl fmt::Display for Unexpected { Unexpected::Bool(b) => write!(f, "boolean `{}`", b), Unexpected::I64(i) => write!(f, "integer 64 bit `{}`", i), Unexpected::I128(i) => write!(f, "integer 128 bit `{}`", i), + Unexpected::U64(i) => write!(f, "unsigned integer 64 bit `{}`", i), + Unexpected::U128(i) => write!(f, "unsigned 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/value.rs b/src/value.rs index 9fb95743..406b00b4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -11,6 +11,8 @@ pub enum ValueKind { Boolean(bool), I64(i64), I128(i128), + U64(u64), + U128(u128), Float(f64), String(String), Table(Table), @@ -80,6 +82,36 @@ impl From for ValueKind { } } +impl From for ValueKind { + fn from(value: u8) -> Self { + ValueKind::U64(value as u64) + } +} + +impl From for ValueKind { + fn from(value: u16) -> Self { + ValueKind::U64(value as u64) + } +} + +impl From for ValueKind { + fn from(value: u32) -> Self { + ValueKind::U64(value as u64) + } +} + +impl From for ValueKind { + fn from(value: u64) -> Self { + ValueKind::U64(value) + } +} + +impl From for ValueKind { + fn from(value: u128) -> Self { + ValueKind::U128(value) + } +} + impl From for ValueKind { fn from(value: f64) -> Self { ValueKind::Float(value) @@ -129,6 +161,8 @@ impl Display for ValueKind { ValueKind::Boolean(value) => write!(f, "{}", value), ValueKind::I64(value) => write!(f, "{}", value), ValueKind::I128(value) => write!(f, "{}", value), + ValueKind::U64(value) => write!(f, "{}", value), + ValueKind::U128(value) => write!(f, "{}", value), ValueKind::Float(value) => write!(f, "{}", value), ValueKind::Nil => write!(f, "nil"), @@ -188,6 +222,8 @@ impl Value { ValueKind::Boolean(value) => Ok(value), ValueKind::I64(value) => Ok(value != 0), ValueKind::I128(value) => Ok(value != 0), + ValueKind::U64(value) => Ok(value != 0), + ValueKind::U128(value) => Ok(value != 0), ValueKind::Float(value) => Ok(value != 0.0), ValueKind::String(ref value) => { @@ -231,7 +267,17 @@ impl Value { ValueKind::I128(value) => Err(ConfigError::invalid_type( self.origin, Unexpected::I128(value), - "an 64 bit or less integer", + "an signed 64 bit or less integer", + )), + ValueKind::U64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U64(value), + "an signed 64 bit or less integer", + )), + ValueKind::U128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U128(value), + "an signed 64 bit or less integer", )), ValueKind::String(ref s) => { @@ -278,6 +324,12 @@ impl Value { match self.kind { ValueKind::I64(value) => Ok(value as i128), ValueKind::I128(value) => Ok(value), + ValueKind::U64(value) => Ok(value as i128), + ValueKind::U128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U128(value), + "an signed 128 bit integer", + )), ValueKind::String(ref s) => { match s.to_lowercase().as_ref() { @@ -318,6 +370,121 @@ impl Value { } } + /// Returns `self` into an u64, if possible. + // FIXME: Should this not be `try_into_*` ? + pub fn into_uint(self) -> Result { + match self.kind { + ValueKind::U64(value) => Ok(value), + ValueKind::U128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U128(value), + "an unsigned 64 bit or less integer", + )), + ValueKind::I64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I64(value), + "an unsigned 64 bit or less integer", + )), + ValueKind::I128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I128(value), + "an unsigned 64 bit or less integer", + )), + + 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 u64), + + // 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 an u128, if possible. + pub fn into_uint128(self) -> Result { + match self.kind { + ValueKind::U64(value) => Ok(value as u128), + ValueKind::U128(value) => Ok(value), + ValueKind::I64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I64(value), + "an unsigned 128 bit or less integer", + )), + ValueKind::I128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::I128(value), + "an unsigned 128 bit or less integer", + )), + + 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 u128), + + // 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 { @@ -343,6 +510,8 @@ impl Value { ValueKind::I64(value) => Ok(value as f64), ValueKind::I128(value) => Ok(value as f64), + ValueKind::U64(value) => Ok(value as f64), + ValueKind::U128(value) => Ok(value as f64), ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }), // Unexpected type @@ -373,6 +542,8 @@ impl Value { ValueKind::Boolean(value) => Ok(value.to_string()), ValueKind::I64(value) => Ok(value.to_string()), ValueKind::I128(value) => Ok(value.to_string()), + ValueKind::U64(value) => Ok(value.to_string()), + ValueKind::U128(value) => Ok(value.to_string()), ValueKind::Float(value) => Ok(value.to_string()), // Cannot convert @@ -421,6 +592,16 @@ impl Value { Unexpected::I128(value), "an array", )), + ValueKind::U64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U64(value), + "an array", + )), + ValueKind::U128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U128(value), + "an array", + )), ValueKind::Boolean(value) => Err(ConfigError::invalid_type( self.origin, Unexpected::Bool(value), @@ -466,6 +647,16 @@ impl Value { Unexpected::I128(value), "a map", )), + ValueKind::U64(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U64(value), + "a map", + )), + ValueKind::U128(value) => Err(ConfigError::invalid_type( + self.origin, + Unexpected::U128(value), + "a map", + )), ValueKind::Boolean(value) => Err(ConfigError::invalid_type( self.origin, Unexpected::Bool(value),