1pub mod sk64 {
2 const SK_MAX_S32: i32 = std::i32::MAX;
3 const SK_MIN_S32: i32 = -SK_MAX_S32;
4
5 pub fn pin_to_s32(x: i64) -> i32 {
6 if x < i64::from(SK_MIN_S32) {
7 return SK_MIN_S32;
8 }
9 if x > i64::from(SK_MAX_S32) {
10 return SK_MAX_S32;
11 }
12 x as i32
13 }
14}
15
16pub mod sk32 {
17 use super::sk64;
18
19 pub fn sat_add(a: i32, b: i32) -> i32 {
20 sk64::pin_to_s32(i64::from(a) + i64::from(b))
21 }
22
23 pub fn sat_sub(a: i32, b: i32) -> i32 {
24 sk64::pin_to_s32(i64::from(a) - i64::from(b))
25 }
26
27 // The original Skia implementations were created
28 // to circumvent an LLVM sanitizer check, but do cause
29 // a "subtract with overflow" for simple cases (see testcase below),
30 // so we keep the naive implementation for now.
31 // Ref:
32 // https://skia-review.googlesource.com/c/skia/+/90544
33 // https://skia-review.googlesource.com/c/skia/+/101881
34 #[allow(dead_code)]
35 pub const fn can_overflow_add(a: i32, b: i32) -> i32 {
36 // ((a as u32) + (b as u32)) as i32
37 a + b
38 }
39
40 pub const fn can_overflow_sub(a: i32, b: i32) -> i32 {
41 // ((a as u32) - (b as u32)) as i32
42 a - b
43 }
44
45 #[test]
46 fn subtraction_with_negative_does_not_overflow() {
47 can_overflow_sub(111, -257);
48 }
49}
50