From 6ef2ad4a61692c509b89243aab560e5eaffae6fa Mon Sep 17 00:00:00 2001 From: BratSinot Date: Mon, 25 Jul 2022 19:37:44 +0200 Subject: Fix FIXME in de.rs and value.rs. --- src/de.rs | 89 ++++++++++++++++++++++++++++++++------------------ src/value.rs | 27 +++++++++++---- tests/integer_range.rs | 10 ++++-- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/src/de.rs b/src/de.rs index 2b4834e..4794ec4 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,13 +1,38 @@ use std::collections::VecDeque; +use std::convert::TryInto; use std::iter::Enumerate; use serde::de; use crate::config::Config; -use crate::error::{ConfigError, Result}; +use crate::error::{ConfigError, Result, Unexpected}; use crate::map::Map; use crate::value::{Table, Value, ValueKind}; +macro_rules! try_convert_number { + (signed, $self:expr, $size:literal) => {{ + let num = $self.into_int()?; + num.try_into().map_err(|_| { + ConfigError::invalid_type( + None, + Unexpected::I64(num), + concat!("an signed ", $size, " bit integer"), + ) + })? + }}; + + (unsigned, $self:expr, $size:literal) => {{ + let num = $self.into_uint()?; + num.try_into().map_err(|_| { + ConfigError::invalid_type( + None, + Unexpected::U64(num), + concat!("an unsigned ", $size, " bit integer"), + ) + })? + }}; +} + impl<'de> de::Deserializer<'de> for Value { type Error = ConfigError; @@ -38,49 +63,50 @@ impl<'de> de::Deserializer<'de> for Value { #[inline] fn deserialize_i8>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i8(self.into_int()? as i8) + let num = try_convert_number!(signed, self, "8"); + visitor.visit_i8(num) } #[inline] fn deserialize_i16>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i16(self.into_int()? as i16) + let num = try_convert_number!(signed, self, "16"); + visitor.visit_i16(num) } #[inline] fn deserialize_i32>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i32(self.into_int()? as i32) + let num = try_convert_number!(signed, self, "32"); + visitor.visit_i32(num) } #[inline] fn deserialize_i64>(self, visitor: V) -> Result { - visitor.visit_i64(self.into_int()?) + let num = try_convert_number!(signed, self, "64"); + visitor.visit_i64(num) } #[inline] fn deserialize_u8>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u8(self.into_uint()? as u8) + let num = try_convert_number!(unsigned, self, "8"); + visitor.visit_u8(num) } #[inline] fn deserialize_u16>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u16(self.into_uint()? as u16) + let num = try_convert_number!(unsigned, self, "16"); + visitor.visit_u16(num) } #[inline] fn deserialize_u32>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u32(self.into_uint()? as u32) + let num = try_convert_number!(unsigned, self, "32"); + visitor.visit_u32(num) } #[inline] fn deserialize_u64>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u64(self.into_uint()? as u64) + let num = try_convert_number!(unsigned, self, "u64"); + visitor.visit_u64(num) } #[inline] @@ -356,49 +382,50 @@ impl<'de> de::Deserializer<'de> for Config { #[inline] fn deserialize_i8>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i8(self.cache.into_int()? as i8) + let num = try_convert_number!(signed, self.cache, "8"); + visitor.visit_i8(num) } #[inline] fn deserialize_i16>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i16(self.cache.into_int()? as i16) + let num = try_convert_number!(signed, self.cache, "16"); + visitor.visit_i16(num) } #[inline] fn deserialize_i32>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_i32(self.cache.into_int()? as i32) + let num = try_convert_number!(signed, self.cache, "32"); + visitor.visit_i32(num) } #[inline] fn deserialize_i64>(self, visitor: V) -> Result { - visitor.visit_i64(self.cache.into_int()?) + let num = try_convert_number!(signed, self.cache, "64"); + visitor.visit_i64(num) } #[inline] fn deserialize_u8>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u8(self.cache.into_int()? as u8) + let num = try_convert_number!(unsigned, self.cache, "8"); + visitor.visit_u8(num) } #[inline] fn deserialize_u16>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u16(self.cache.into_int()? as u16) + let num = try_convert_number!(unsigned, self.cache, "16"); + visitor.visit_u16(num) } #[inline] fn deserialize_u32>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u32(self.cache.into_int()? as u32) + let num = try_convert_number!(unsigned, self.cache, "32"); + visitor.visit_u32(num) } #[inline] fn deserialize_u64>(self, visitor: V) -> Result { - // FIXME: This should *fail* if the value does not fit in the requets integer type - visitor.visit_u64(self.cache.into_int()? as u64) + let num = try_convert_number!(unsigned, self.cache, "64"); + visitor.visit_u64(num) } #[inline] diff --git a/src/value.rs b/src/value.rs index c9536f7..40cbfe6 100644 --- a/src/value.rs +++ b/src/value.rs @@ -761,15 +761,30 @@ impl<'de> Deserialize<'de> for Value { } #[inline] - fn visit_u64(self, value: u64) -> ::std::result::Result { - // FIXME: This is bad - Ok((value as i64).into()) + fn visit_u64(self, value: u64) -> ::std::result::Result + where + E: ::serde::de::Error, + { + let num: i64 = value.try_into().map_err(|_| { + E::invalid_type(::serde::de::Unexpected::Unsigned(value), &self) + })?; + Ok(num.into()) } #[inline] - fn visit_u128(self, value: u128) -> ::std::result::Result { - // FIXME: This is bad - Ok((value as i128).into()) + fn visit_u128(self, value: u128) -> ::std::result::Result + where + E: ::serde::de::Error, + { + let num: i128 = value.try_into().map_err(|_| { + E::invalid_type( + ::serde::de::Unexpected::Other( + format!("integer `{value}` as u128").as_str(), + ), + &self, + ) + })?; + Ok(num.into()) } #[inline] diff --git a/tests/integer_range.rs b/tests/integer_range.rs index 7777ef2..e80a2f2 100644 --- a/tests/integer_range.rs +++ b/tests/integer_range.rs @@ -13,8 +13,14 @@ fn wrapping_u16() { .build() .unwrap(); - let port: u16 = c.get("settings.port").unwrap(); - assert_eq!(port, 464); + // FIXME: Can't compare ConfigError, because Unexpected are private. + let _port_error = c.get::("settings.port").unwrap_err(); + /* + assert!(matches!( + Err(ConfigError::invalid_type(None, config::Unexpected::U64(66000), "an unsigned 16 bit integer"),) + port_error + )); + */ } #[test] -- cgit v1.2.3