diff --git a/serde_json_path_core/src/spec/integer.rs b/serde_json_path_core/src/spec/integer.rs index 6fb8b2c..307abc6 100644 --- a/serde_json_path_core/src/spec/integer.rs +++ b/serde_json_path_core/src/spec/integer.rs @@ -22,19 +22,19 @@ const MAX: i64 = 9_007_199_254_740_992 - 1; /// The minimum allowed value (-2^53) + 1 const MIN: i64 = -9_007_199_254_740_992 + 1; +fn check_i64(v: i64) -> bool { + (MIN..=MAX).contains(&v) +} + impl Integer { fn try_new(value: i64) -> Result { - if !(MIN..=MAX).contains(&value) { - Err(IntegerError::OutOfBounds) - } else { + if check_i64(value) { Ok(Self(value)) + } else { + Err(IntegerError::OutOfBounds) } } - fn check(&self) -> bool { - (MIN..=MAX).contains(&self.0) - } - /// Produce an [`Integer`] with the value 0 pub fn zero() -> Self { Self(0) @@ -52,32 +52,30 @@ impl Integer { Self::try_new(value).expect("value is out of the valid range") } - /// Take the absolute value, producing `None` if the resulting value is outside - /// the valid range [-(253)+1, (253)-1]. - pub fn checked_abs(mut self) -> Option { - self.0 = self.0.checked_abs()?; - self.check().then_some(self) + /// Take the absolute value, producing a new instance of [`Integer`] + pub fn abs(&self) -> Self { + Self(self.0.abs()) } - /// Add the two values, producing `None` if the resulting value is outside the - /// valid range [-(253)+1, (253)-1]. - pub fn checked_add(mut self, rhs: Self) -> Option { - self.0 = self.0.checked_add(rhs.0)?; - self.check().then_some(self) + /// Add the two values, producing a new instance of [`Integer`] or `None` if the + /// resulting value is outside the valid range [-(253)+1, (253)-1] + pub fn checked_add(&self, rhs: Self) -> Option { + let i = self.0.checked_add(rhs.0)?; + check_i64(i).then_some(Self(i)) } - /// Subtract the `rhs` from `self`, producing `None` if the resulting value is - /// outside the valid range [-(253)+1, (253)-1]. - pub fn checked_sub(mut self, rhs: Self) -> Option { - self.0 = self.0.checked_sub(rhs.0)?; - self.check().then_some(self) + /// Subtract the `rhs` from `self`, producing a new instance of [`Integer`] or `None` + /// if the resulting value is outside the valid range [-(253)+1, (253)-1]. + pub fn checked_sub(&self, rhs: Self) -> Option { + let i = self.0.checked_sub(rhs.0)?; + check_i64(i).then_some(Self(i)) } - /// Multiply the two values, producing `None` if the resulting value is outside - /// the valid range [-(253)+1, (253)-1]. - pub fn checked_mul(mut self, rhs: Self) -> Option { - self.0 = self.0.checked_mul(rhs.0)?; - self.check().then_some(self) + /// Multiply the two values, producing a new instance of [`Integer`] or `None` if the resulting + /// value is outside the valid range [-(253)+1, (253)-1]. + pub fn checked_mul(&self, rhs: Self) -> Option { + let i = self.0.checked_mul(rhs.0)?; + check_i64(i).then_some(Self(i)) } } @@ -89,16 +87,43 @@ impl TryFrom for Integer { } } -impl TryFrom for Integer { - type Error = IntegerError; +macro_rules! impl_try_from { + ($type:ty) => { + impl TryFrom<$type> for Integer { + type Error = IntegerError; - fn try_from(value: usize) -> Result { - i64::try_from(value) - .map_err(|_| IntegerError::OutOfBounds) - .and_then(Self::try_new) - } + fn try_from(value: $type) -> Result { + i64::try_from(value) + .map_err(|_| IntegerError::OutOfBounds) + .and_then(Self::try_from) + } + } + }; } +impl_try_from!(i128); +impl_try_from!(u64); +impl_try_from!(u128); +impl_try_from!(usize); +impl_try_from!(isize); + +macro_rules! impl_from { + ($type:ty) => { + impl From<$type> for Integer { + fn from(value: $type) -> Self { + Self(value.into()) + } + } + }; +} + +impl_from!(i8); +impl_from!(i16); +impl_from!(i32); +impl_from!(u8); +impl_from!(u16); +impl_from!(u32); + impl FromStr for Integer { type Err = IntegerError; diff --git a/serde_json_path_core/src/spec/selector/index.rs b/serde_json_path_core/src/spec/selector/index.rs index 732b7d8..e64bae6 100644 --- a/serde_json_path_core/src/spec/selector/index.rs +++ b/serde_json_path_core/src/spec/selector/index.rs @@ -24,9 +24,9 @@ impl Queryable for Index { fn query<'b>(&self, current: &'b Value, _root: &'b Value) -> Vec<&'b Value> { if let Some(list) = current.as_array() { if self.0 < 0 { - self.0 - .checked_abs() - .and_then(|i| usize::try_from(i).ok()) + let abs = self.0.abs(); + usize::try_from(abs) + .ok() .and_then(|i| list.len().checked_sub(i)) .and_then(|i| list.get(i)) .into_iter() @@ -51,9 +51,9 @@ impl Queryable for Index { ) -> Vec> { if let Some((index, node)) = current.as_array().and_then(|list| { if self.0 < 0 { - self.0 - .checked_abs() - .and_then(|i| usize::try_from(i).ok()) + let abs = self.0.abs(); + usize::try_from(abs) + .ok() .and_then(|i| list.len().checked_sub(i)) .and_then(|i| list.get(i).map(|v| (i, v))) } else { diff --git a/serde_json_path_core/src/spec/selector/slice.rs b/serde_json_path_core/src/spec/selector/slice.rs index 3eb7750..77f460f 100644 --- a/serde_json_path_core/src/spec/selector/slice.rs +++ b/serde_json_path_core/src/spec/selector/slice.rs @@ -235,6 +235,6 @@ fn normalize_slice_index(index: Integer, len: Integer) -> Option { if index >= 0 { Some(index) } else { - index.checked_abs().and_then(|i| len.checked_sub(i)) + len.checked_sub(index.abs()) } }