Skip to content

Commit 4bdf687

Browse files
committed
Saturating extents
1 parent 4e77c05 commit 4bdf687

File tree

7 files changed

+156
-7
lines changed

7 files changed

+156
-7
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## Unreleased
9+
10+
### Added
11+
12+
- Trait `StdNumOps` defines saturating math operations. All unit types, `Size`,
13+
and `Point` implement this trait.
14+
- `Rect::saturating_extents` returns the extents of a rectangle using saturating
15+
math.
16+
817
## v0.4.2 (2024-10-20)
918

1019
### Added

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ mod tables;
1919
mod traits;
2020
pub use traits::{
2121
Abs, FloatConversion, FloatOrInt, FromComponents, IntoComponents, IntoSigned, IntoUnsigned,
22-
Lp2D, PixelScaling, Pow, Px2D, Ranged, Roots, Round, ScreenScale, ScreenUnit, UPx2D, Unit,
23-
UnscaledUnit, Zero,
22+
Lp2D, PixelScaling, Pow, Px2D, Ranged, Roots, Round, ScreenScale, ScreenUnit, StdNumOps, UPx2D,
23+
Unit, UnscaledUnit, Zero,
2424
};
2525
/// The measurement units supported by figures.
2626
pub mod units;

src/point.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ops::{Add, Mul, Sub};
22

3-
use crate::traits::{IntoComponents, Roots};
3+
use crate::traits::{IntoComponents, Roots, StdNumOps};
44
use crate::utils::vec_ord;
55
use crate::{Angle, Fraction, Zero};
66

@@ -240,3 +240,36 @@ impl From<Point<crate::units::UPx>> for wgpu::Origin3d {
240240
}
241241
}
242242
}
243+
244+
impl<T> StdNumOps for Point<T>
245+
where
246+
T: StdNumOps,
247+
{
248+
fn saturating_add(self, other: Self) -> Self {
249+
Self::new(
250+
self.x.saturating_add(other.x),
251+
self.y.saturating_add(other.y),
252+
)
253+
}
254+
255+
fn saturating_mul(self, other: Self) -> Self {
256+
Self::new(
257+
self.x.saturating_mul(other.x),
258+
self.y.saturating_mul(other.y),
259+
)
260+
}
261+
262+
fn saturating_div(self, other: Self) -> Self {
263+
Self::new(
264+
self.x.saturating_div(other.x),
265+
self.y.saturating_div(other.y),
266+
)
267+
}
268+
269+
fn saturating_sub(self, other: Self) -> Self {
270+
Self::new(
271+
self.x.saturating_sub(other.x),
272+
self.y.saturating_sub(other.y),
273+
)
274+
}
275+
}

src/rect.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ops::{Add, AddAssign, Sub, SubAssign};
22

3-
use crate::traits::{IntoSigned, IntoUnsigned, Ranged};
4-
use crate::{FloatConversion, Point, Round, Size, Zero};
3+
use crate::traits::{IntoSigned, IntoUnsigned, Ranged, StdNumOps};
4+
use crate::{FloatConversion, IntoComponents, Point, Round, Size, Zero};
55

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

216+
impl<Unit> Rect<Unit>
217+
where
218+
Unit: StdNumOps + Ord + Copy,
219+
{
220+
/// Returns the top-left and bottom-right points of this rectangle.
221+
///
222+
/// The first point returned will always be the top-right point, even if the
223+
/// size of the rectangle is negative.
224+
///
225+
/// The returned extent point will be saturated instead of wrapping.
226+
pub fn saturating_extents(&self) -> (Point<Unit>, Point<Unit>) {
227+
let extent = self.origin.saturating_add(self.size.to_vec());
228+
(
229+
Point::new(self.origin.x.min(extent.x), self.origin.y.min(extent.y)),
230+
Point::new(self.origin.x.max(extent.x), self.origin.y.max(extent.y)),
231+
)
232+
}
233+
}
234+
216235
impl<Unit> Default for Rect<Unit>
217236
where
218237
Unit: Default,

src/size.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cmp::Ordering;
22
use std::ops::Mul;
33

4-
use crate::traits::IntoComponents;
4+
use crate::traits::{IntoComponents, StdNumOps};
55
use crate::utils::vec_ord;
66
use crate::Point;
77

@@ -190,3 +190,36 @@ impl From<Size<crate::units::Px>> for winit::dpi::PhysicalSize<i32> {
190190
}
191191
}
192192
}
193+
194+
impl<T> StdNumOps for Size<T>
195+
where
196+
T: StdNumOps,
197+
{
198+
fn saturating_add(self, other: Self) -> Self {
199+
Self::new(
200+
self.width.saturating_add(other.width),
201+
self.height.saturating_add(other.height),
202+
)
203+
}
204+
205+
fn saturating_mul(self, other: Self) -> Self {
206+
Self::new(
207+
self.width.saturating_mul(other.width),
208+
self.height.saturating_mul(other.height),
209+
)
210+
}
211+
212+
fn saturating_div(self, other: Self) -> Self {
213+
Self::new(
214+
self.width.saturating_div(other.width),
215+
self.height.saturating_div(other.height),
216+
)
217+
}
218+
219+
fn saturating_sub(self, other: Self) -> Self {
220+
Self::new(
221+
self.width.saturating_sub(other.width),
222+
self.height.saturating_sub(other.height),
223+
)
224+
}
225+
}

src/traits.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,43 @@ pub trait Unit:
423423
{
424424
}
425425

426+
/// Common number operations available on number types in Rust that aren't
427+
/// available as traits.
428+
pub trait StdNumOps {
429+
/// Adds `self` and `other`, saturating instead of overflowing.
430+
fn saturating_add(self, other: Self) -> Self;
431+
/// Multiplies `self` and `other`, saturating instead of overflowing.
432+
fn saturating_mul(self, other: Self) -> Self;
433+
/// Divides `self` by `other`, saturating instead of overflowing.
434+
fn saturating_div(self, other: Self) -> Self;
435+
/// Subtracts `other` from `self`, saturating instead of overflowing.
436+
fn saturating_sub(self, other: Self) -> Self;
437+
}
438+
439+
macro_rules! impl_std_num_ops {
440+
($type:ident) => {
441+
impl StdNumOps for $type {
442+
fn saturating_add(self, other: Self) -> Self {
443+
self.saturating_add(other)
444+
}
445+
446+
fn saturating_mul(self, other: Self) -> Self {
447+
self.saturating_mul(other)
448+
}
449+
450+
fn saturating_div(self, other: Self) -> Self {
451+
self.saturating_div(other)
452+
}
453+
454+
fn saturating_sub(self, other: Self) -> Self {
455+
self.saturating_sub(other)
456+
}
457+
}
458+
};
459+
}
460+
461+
impl_std_num_ops!(u8);
462+
426463
impl<T> Unit for T where
427464
T: FloatConversion<Float = f32>
428465
+ Add<Output = Self>

src/units.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use intentional::{Cast, CastFrom};
77

88
use crate::traits::{
99
Abs, FloatConversion, IntoComponents, IntoSigned, IntoUnsigned, Pow, Roots, Round, ScreenScale,
10-
UnscaledUnit, Zero,
10+
StdNumOps, UnscaledUnit, Zero,
1111
};
1212
use crate::Fraction;
1313

@@ -353,6 +353,24 @@ macro_rules! define_integer_type {
353353
Self(f64::from(self.0).cbrt().cast())
354354
}
355355
}
356+
357+
impl StdNumOps for $name {
358+
fn saturating_add(self, other: Self) -> Self {
359+
self.saturating_add(other)
360+
}
361+
362+
fn saturating_mul(self, other: Self) -> Self {
363+
self.saturating_mul(other)
364+
}
365+
366+
fn saturating_div(self, other: Self) -> Self {
367+
self.saturating_div(other)
368+
}
369+
370+
fn saturating_sub(self, other: Self) -> Self {
371+
self.saturating_sub(other)
372+
}
373+
}
356374
};
357375
}
358376

0 commit comments

Comments
 (0)