diff --git a/lib/oxsdatatypes/src/date_time.rs b/lib/oxsdatatypes/src/date_time.rs index 63c45f0b..38508f66 100644 --- a/lib/oxsdatatypes/src/date_time.rs +++ b/lib/oxsdatatypes/src/date_time.rs @@ -188,8 +188,11 @@ impl DateTime { self.checked_sub_day_time_duration(rhs) } else { Some(Self { - timestamp: Timestamp::new(&date_time_plus_duration(-rhs, &self.properties())?) - .ok()?, + timestamp: Timestamp::new(&date_time_plus_duration( + rhs.checked_neg()?, + &self.properties(), + )?) + .ok()?, }) } } diff --git a/lib/oxsdatatypes/src/decimal.rs b/lib/oxsdatatypes/src/decimal.rs index 1b6fa6cc..73335f96 100644 --- a/lib/oxsdatatypes/src/decimal.rs +++ b/lib/oxsdatatypes/src/decimal.rs @@ -141,6 +141,14 @@ impl Decimal { }) } + /// [op:numeric-unary-minus](https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus) + #[inline] + pub fn checked_neg(&self) -> Option { + Some(Self { + value: self.value.checked_neg()?, + }) + } + /// [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs) #[inline] pub const fn abs(&self) -> Self { @@ -698,7 +706,10 @@ mod tests { fn add() { assert!(Decimal::MIN.checked_add(Decimal::STEP).is_some()); assert!(Decimal::MAX.checked_add(Decimal::STEP).is_none()); - assert_eq!(Decimal::MAX.checked_add(Decimal::MIN), Some(-Decimal::STEP)); + assert_eq!( + Decimal::MAX.checked_add(Decimal::MIN), + Decimal::STEP.checked_neg() + ); } #[test] diff --git a/lib/oxsdatatypes/src/duration.rs b/lib/oxsdatatypes/src/duration.rs index 0bc9d2bf..55fd6001 100644 --- a/lib/oxsdatatypes/src/duration.rs +++ b/lib/oxsdatatypes/src/duration.rs @@ -107,6 +107,14 @@ impl Duration { }) } + #[inline] + pub fn checked_neg(&self) -> Option { + Some(Self { + year_month: self.year_month.checked_neg()?, + day_time: self.day_time.checked_neg()?, + }) + } + /// Checks if the two values are [identical](https://www.w3.org/TR/xmlschema11-2/#identity). #[inline] pub fn is_identical_with(&self, other: &Self) -> bool { @@ -301,6 +309,13 @@ impl YearMonthDuration { }) } + #[inline] + pub fn checked_neg(&self) -> Option { + Some(Self { + months: self.months.checked_neg()?, + }) + } + /// Checks if the two values are [identical](https://www.w3.org/TR/xmlschema11-2/#identity). #[inline] pub fn is_identical_with(&self, other: &Self) -> bool { @@ -467,6 +482,13 @@ impl DayTimeDuration { }) } + #[inline] + pub fn checked_neg(&self) -> Option { + Some(Self { + seconds: self.seconds.checked_neg()?, + }) + } + /// Checks if the two values are [identical](https://www.w3.org/TR/xmlschema11-2/#identity). #[inline] pub fn is_identical_with(&self, other: &Self) -> bool { diff --git a/lib/oxsdatatypes/src/integer.rs b/lib/oxsdatatypes/src/integer.rs index 46175fc3..0c9d90e5 100644 --- a/lib/oxsdatatypes/src/integer.rs +++ b/lib/oxsdatatypes/src/integer.rs @@ -73,6 +73,14 @@ impl Integer { }) } + /// [op:numeric-unary-minus](https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus) + #[inline] + pub fn checked_neg(&self) -> Option { + Some(Self { + value: self.value.checked_neg()?, + }) + } + /// [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs) #[inline] pub const fn abs(&self) -> Self { diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 4d2d738f..e92c66cf 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -1189,11 +1189,13 @@ impl SimpleEvaluator { Rc::new(move |tuple| match e(tuple)? { EncodedTerm::FloatLiteral(value) => Some((-value).into()), EncodedTerm::DoubleLiteral(value) => Some((-value).into()), - EncodedTerm::IntegerLiteral(value) => Some((-value).into()), - EncodedTerm::DecimalLiteral(value) => Some((-value).into()), - EncodedTerm::DurationLiteral(value) => Some((-value).into()), - EncodedTerm::YearMonthDurationLiteral(value) => Some((-value).into()), - EncodedTerm::DayTimeDurationLiteral(value) => Some((-value).into()), + EncodedTerm::IntegerLiteral(value) => Some(value.checked_neg()?.into()), + EncodedTerm::DecimalLiteral(value) => Some(value.checked_neg()?.into()), + EncodedTerm::DurationLiteral(value) => Some(value.checked_neg()?.into()), + EncodedTerm::YearMonthDurationLiteral(value) => { + Some(value.checked_neg()?.into()) + } + EncodedTerm::DayTimeDurationLiteral(value) => Some(value.checked_neg()?.into()), _ => None, }) }