Skip to main content

vyre_std/arith/
unsigned.rs

1/// Minimum of two `u8` values.
2#[must_use]
3#[inline]
4pub fn min_u8(a: u8, b: u8) -> u8 {
5    if a < b {
6        a
7    } else {
8        b
9    }
10}
11/// Minimum of two `u16` values.
12#[must_use]
13#[inline]
14pub fn min_u16(a: u16, b: u16) -> u16 {
15    if a < b {
16        a
17    } else {
18        b
19    }
20}
21/// Minimum of two `u32` values.
22#[must_use]
23#[inline]
24pub fn min_u32(a: u32, b: u32) -> u32 {
25    if a < b {
26        a
27    } else {
28        b
29    }
30}
31/// Minimum of two `u64` values.
32#[must_use]
33#[inline]
34pub fn min_u64(a: u64, b: u64) -> u64 {
35    if a < b {
36        a
37    } else {
38        b
39    }
40}
41
42/// Maximum of two `u8` values.
43#[must_use]
44#[inline]
45pub fn max_u8(a: u8, b: u8) -> u8 {
46    if a > b {
47        a
48    } else {
49        b
50    }
51}
52/// Maximum of two `u16` values.
53#[must_use]
54#[inline]
55pub fn max_u16(a: u16, b: u16) -> u16 {
56    if a > b {
57        a
58    } else {
59        b
60    }
61}
62/// Maximum of two `u32` values.
63#[must_use]
64#[inline]
65pub fn max_u32(a: u32, b: u32) -> u32 {
66    if a > b {
67        a
68    } else {
69        b
70    }
71}
72/// Maximum of two `u64` values.
73#[must_use]
74#[inline]
75pub fn max_u64(a: u64, b: u64) -> u64 {
76    if a > b {
77        a
78    } else {
79        b
80    }
81}
82
83/// Clamp `x` to the inclusive range `[lo, hi]` for `u32`.
84///
85/// # Panics
86/// Panics (in debug **and** release) if `lo > hi`. Matches stdlib
87/// `u32::clamp` semantics — a silently-returned wrong answer on inverted
88/// bounds is a latent bug at internet scale.
89#[must_use]
90#[inline]
91pub fn clamp_u32(x: u32, lo: u32, hi: u32) -> u32 {
92    assert!(lo <= hi, "Fix: clamp_u32 called with lo > hi");
93    min_u32(max_u32(x, lo), hi)
94}
95/// Clamp `x` to the inclusive range `[lo, hi]` for `u64`.
96///
97/// # Panics
98/// Panics if `lo > hi`.
99#[must_use]
100#[inline]
101pub fn clamp_u64(x: u64, lo: u64, hi: u64) -> u64 {
102    assert!(lo <= hi, "Fix: clamp_u64 called with lo > hi");
103    min_u64(max_u64(x, lo), hi)
104}
105/// Clamp `x` to the inclusive range `[lo, hi]` for `u16`.
106///
107/// # Panics
108/// Panics if `lo > hi`.
109#[must_use]
110#[inline]
111pub fn clamp_u16(x: u16, lo: u16, hi: u16) -> u16 {
112    assert!(lo <= hi, "Fix: clamp_u16 called with lo > hi");
113    min_u16(max_u16(x, lo), hi)
114}
115/// Clamp `x` to the inclusive range `[lo, hi]` for `u8`.
116///
117/// # Panics
118/// Panics if `lo > hi`.
119#[must_use]
120#[inline]
121pub fn clamp_u8(x: u8, lo: u8, hi: u8) -> u8 {
122    assert!(lo <= hi, "Fix: clamp_u8 called with lo > hi");
123    min_u8(max_u8(x, lo), hi)
124}
125
126/// Overflow-safe midpoint for `u32`: `a/2 + b/2 + (a & b & 1)`.
127#[must_use]
128#[inline]
129pub fn midpoint_u32(a: u32, b: u32) -> u32 {
130    (a & b).wrapping_add((a ^ b) >> 1)
131}
132/// Overflow-safe midpoint for `u64`.
133#[must_use]
134#[inline]
135pub fn midpoint_u64(a: u64, b: u64) -> u64 {
136    (a & b).wrapping_add((a ^ b) >> 1)
137}
138/// Overflow-safe midpoint for `u16`.
139#[must_use]
140#[inline]
141pub fn midpoint_u16(a: u16, b: u16) -> u16 {
142    (a & b).wrapping_add((a ^ b) >> 1)
143}
144/// Overflow-safe midpoint for `u8`.
145#[must_use]
146#[inline]
147pub fn midpoint_u8(a: u8, b: u8) -> u8 {
148    (a & b).wrapping_add((a ^ b) >> 1)
149}
150
151/// Absolute difference between two `u8` values.
152#[must_use]
153#[inline]
154pub fn abs_diff_u8(a: u8, b: u8) -> u8 {
155    a.abs_diff(b)
156}
157/// Absolute difference between two `u16` values.
158#[must_use]
159#[inline]
160pub fn abs_diff_u16(a: u16, b: u16) -> u16 {
161    a.abs_diff(b)
162}
163/// Absolute difference between two `u32` values.
164#[must_use]
165#[inline]
166pub fn abs_diff_u32(a: u32, b: u32) -> u32 {
167    a.abs_diff(b)
168}
169/// Absolute difference between two `u64` values.
170#[must_use]
171#[inline]
172pub fn abs_diff_u64(a: u64, b: u64) -> u64 {
173    a.abs_diff(b)
174}
175
176// --- division helpers (unsigned) ----------------------------------------
177
178/// Ceiling division for unsigned `u32`.
179///
180/// # Panics
181/// Panics if `denom == 0`.
182#[must_use]
183#[inline]
184pub fn div_ceil_u32(numer: u32, denom: u32) -> u32 {
185    assert!(denom != 0, "Fix: div_ceil called with zero denominator");
186    numer.div_ceil(denom)
187}
188/// Ceiling division for unsigned `u64`.
189#[must_use]
190#[inline]
191pub fn div_ceil_u64(numer: u64, denom: u64) -> u64 {
192    assert!(denom != 0, "Fix: div_ceil called with zero denominator");
193    numer.div_ceil(denom)
194}
195/// Floor division for unsigned `u32`.
196#[must_use]
197#[inline]
198pub fn div_floor_u32(numer: u32, denom: u32) -> u32 {
199    assert!(denom != 0, "Fix: div_floor called with zero denominator");
200    numer / denom
201}
202/// Floor division for unsigned `u64`.
203#[must_use]
204#[inline]
205pub fn div_floor_u64(numer: u64, denom: u64) -> u64 {
206    assert!(denom != 0, "Fix: div_floor called with zero denominator");
207    numer / denom
208}
209/// Round-to-nearest-half-up division for `u8`.
210///
211/// Uses a `u16` intermediate so `(numer + denom/2)` cannot overflow even
212/// at `numer == u8::MAX`.
213///
214/// # Panics
215/// Panics if `denom == 0`.
216#[must_use]
217#[inline]
218pub fn div_round_u8(numer: u8, denom: u8) -> u8 {
219    assert!(denom != 0, "Fix: div_round_u8 called with zero denominator");
220    let n = numer as u16;
221    let d = denom as u16;
222    ((n + d / 2) / d) as u8
223}
224/// Round-to-nearest-half-up division for `u16`.
225///
226/// # Panics
227/// Panics if `denom == 0`.
228#[must_use]
229#[inline]
230pub fn div_round_u16(numer: u16, denom: u16) -> u16 {
231    assert!(
232        denom != 0,
233        "Fix: div_round_u16 called with zero denominator"
234    );
235    let n = numer as u32;
236    let d = denom as u32;
237    ((n + d / 2) / d) as u16
238}
239/// Round-to-nearest-half-up division for `u32`.
240///
241/// Uses a `u64` intermediate to avoid the overflow `(numer + denom/2)`
242/// suffered when `numer` is near `u32::MAX` — a silent wrong result that
243/// becomes a correctness bug at any scale.
244///
245/// # Panics
246/// Panics if `denom == 0`.
247#[must_use]
248#[inline]
249pub fn div_round_u32(numer: u32, denom: u32) -> u32 {
250    assert!(
251        denom != 0,
252        "Fix: div_round_u32 called with zero denominator"
253    );
254    let n = u64::from(numer);
255    let d = u64::from(denom);
256    ((n + d / 2) / d) as u32
257}
258/// Round-to-nearest-half-up division for `u64`.
259///
260/// Uses a `u128` intermediate to avoid `(numer + denom/2)` overflow near
261/// `u64::MAX`.
262///
263/// # Panics
264/// Panics if `denom == 0`.
265#[must_use]
266#[inline]
267pub fn div_round_u64(numer: u64, denom: u64) -> u64 {
268    assert!(
269        denom != 0,
270        "Fix: div_round_u64 called with zero denominator"
271    );
272    let n = u128::from(numer);
273    let d = u128::from(denom);
274    ((n + d / 2) / d) as u64
275}
276
277// --- min / max / clamp / abs_diff / midpoint (signed) -------------------