Skip to content

Commit

Permalink
Saturating extents
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Nov 19, 2024
1 parent 4e77c05 commit 4bdf687
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 7 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Trait `StdNumOps` defines saturating math operations. All unit types, `Size`,
and `Point` implement this trait.
- `Rect::saturating_extents` returns the extents of a rectangle using saturating
math.

## v0.4.2 (2024-10-20)

### Added
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ mod tables;
mod traits;
pub use traits::{
Abs, FloatConversion, FloatOrInt, FromComponents, IntoComponents, IntoSigned, IntoUnsigned,
Lp2D, PixelScaling, Pow, Px2D, Ranged, Roots, Round, ScreenScale, ScreenUnit, UPx2D, Unit,
UnscaledUnit, Zero,
Lp2D, PixelScaling, Pow, Px2D, Ranged, Roots, Round, ScreenScale, ScreenUnit, StdNumOps, UPx2D,
Unit, UnscaledUnit, Zero,
};
/// The measurement units supported by figures.
pub mod units;
Expand Down
35 changes: 34 additions & 1 deletion src/point.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::ops::{Add, Mul, Sub};

use crate::traits::{IntoComponents, Roots};
use crate::traits::{IntoComponents, Roots, StdNumOps};
use crate::utils::vec_ord;
use crate::{Angle, Fraction, Zero};

Expand Down Expand Up @@ -240,3 +240,36 @@ impl From<Point<crate::units::UPx>> for wgpu::Origin3d {
}
}
}

impl<T> StdNumOps for Point<T>
where
T: StdNumOps,
{
fn saturating_add(self, other: Self) -> Self {
Self::new(
self.x.saturating_add(other.x),
self.y.saturating_add(other.y),
)
}

fn saturating_mul(self, other: Self) -> Self {
Self::new(
self.x.saturating_mul(other.x),
self.y.saturating_mul(other.y),
)
}

fn saturating_div(self, other: Self) -> Self {
Self::new(
self.x.saturating_div(other.x),
self.y.saturating_div(other.y),
)
}

fn saturating_sub(self, other: Self) -> Self {
Self::new(
self.x.saturating_sub(other.x),
self.y.saturating_sub(other.y),
)
}
}
23 changes: 21 additions & 2 deletions src/rect.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ops::{Add, AddAssign, Sub, SubAssign};

use crate::traits::{IntoSigned, IntoUnsigned, Ranged};
use crate::{FloatConversion, Point, Round, Size, Zero};
use crate::traits::{IntoSigned, IntoUnsigned, Ranged, StdNumOps};
use crate::{FloatConversion, IntoComponents, Point, Round, Size, Zero};

/// A 2d area expressed as an origin ([`Point`]) and a [`Size`].
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
Expand Down Expand Up @@ -213,6 +213,25 @@ where
}
}

impl<Unit> Rect<Unit>
where
Unit: StdNumOps + Ord + Copy,
{
/// Returns the top-left and bottom-right points of this rectangle.
///
/// The first point returned will always be the top-right point, even if the
/// size of the rectangle is negative.
///
/// The returned extent point will be saturated instead of wrapping.
pub fn saturating_extents(&self) -> (Point<Unit>, Point<Unit>) {
let extent = self.origin.saturating_add(self.size.to_vec());
(
Point::new(self.origin.x.min(extent.x), self.origin.y.min(extent.y)),
Point::new(self.origin.x.max(extent.x), self.origin.y.max(extent.y)),
)
}
}

impl<Unit> Default for Rect<Unit>
where
Unit: Default,
Expand Down
35 changes: 34 additions & 1 deletion src/size.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::cmp::Ordering;
use std::ops::Mul;

use crate::traits::IntoComponents;
use crate::traits::{IntoComponents, StdNumOps};
use crate::utils::vec_ord;
use crate::Point;

Expand Down Expand Up @@ -190,3 +190,36 @@ impl From<Size<crate::units::Px>> for winit::dpi::PhysicalSize<i32> {
}
}
}

impl<T> StdNumOps for Size<T>
where
T: StdNumOps,
{
fn saturating_add(self, other: Self) -> Self {
Self::new(
self.width.saturating_add(other.width),
self.height.saturating_add(other.height),
)
}

fn saturating_mul(self, other: Self) -> Self {
Self::new(
self.width.saturating_mul(other.width),
self.height.saturating_mul(other.height),
)
}

fn saturating_div(self, other: Self) -> Self {
Self::new(
self.width.saturating_div(other.width),
self.height.saturating_div(other.height),
)
}

fn saturating_sub(self, other: Self) -> Self {
Self::new(
self.width.saturating_sub(other.width),
self.height.saturating_sub(other.height),
)
}
}
37 changes: 37 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,43 @@ pub trait Unit:
{
}

/// Common number operations available on number types in Rust that aren't
/// available as traits.
pub trait StdNumOps {
/// Adds `self` and `other`, saturating instead of overflowing.
fn saturating_add(self, other: Self) -> Self;
/// Multiplies `self` and `other`, saturating instead of overflowing.
fn saturating_mul(self, other: Self) -> Self;
/// Divides `self` by `other`, saturating instead of overflowing.
fn saturating_div(self, other: Self) -> Self;
/// Subtracts `other` from `self`, saturating instead of overflowing.
fn saturating_sub(self, other: Self) -> Self;
}

macro_rules! impl_std_num_ops {
($type:ident) => {
impl StdNumOps for $type {
fn saturating_add(self, other: Self) -> Self {
self.saturating_add(other)
}

fn saturating_mul(self, other: Self) -> Self {
self.saturating_mul(other)
}

fn saturating_div(self, other: Self) -> Self {
self.saturating_div(other)
}

fn saturating_sub(self, other: Self) -> Self {
self.saturating_sub(other)
}
}
};
}

impl_std_num_ops!(u8);

impl<T> Unit for T where
T: FloatConversion<Float = f32>
+ Add<Output = Self>
Expand Down
20 changes: 19 additions & 1 deletion src/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use intentional::{Cast, CastFrom};

use crate::traits::{
Abs, FloatConversion, IntoComponents, IntoSigned, IntoUnsigned, Pow, Roots, Round, ScreenScale,
UnscaledUnit, Zero,
StdNumOps, UnscaledUnit, Zero,
};
use crate::Fraction;

Expand Down Expand Up @@ -353,6 +353,24 @@ macro_rules! define_integer_type {
Self(f64::from(self.0).cbrt().cast())
}
}

impl StdNumOps for $name {
fn saturating_add(self, other: Self) -> Self {
self.saturating_add(other)
}

fn saturating_mul(self, other: Self) -> Self {
self.saturating_mul(other)
}

fn saturating_div(self, other: Self) -> Self {
self.saturating_div(other)
}

fn saturating_sub(self, other: Self) -> Self {
self.saturating_sub(other)
}
}
};
}

Expand Down

0 comments on commit 4bdf687

Please sign in to comment.