objc2_foundation/
geometry.rs

1use objc2::encode::{Encode, Encoding, RefEncode};
2use objc2::ffi::NSUInteger;
3
4#[cfg(feature = "objc2-core-foundation")]
5use objc2_core_foundation::{CGPoint, CGRect, CGSize};
6
7/// A point in a Cartesian coordinate system.
8///
9/// This is a convenience alias for [`CGPoint`]. For ease of use, it is
10/// available on all platforms, though in practice it is only useful on macOS.
11///
12/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nspoint?language=objc).
13#[cfg(feature = "objc2-core-foundation")]
14pub type NSPoint = CGPoint;
15
16/// A two-dimensional size.
17///
18/// This is a convenience alias for [`CGSize`]. For ease of use, it is
19/// available on all platforms, though in practice it is only useful on macOS.
20///
21/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nssize?language=objc).
22#[cfg(feature = "objc2-core-foundation")]
23pub type NSSize = CGSize;
24
25/// A rectangle.
26///
27/// This is a convenience alias for [`CGRect`]. For ease of use, it is
28/// available on all platforms, though in practice it is only useful on macOS.
29///
30/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsrect?language=objc).
31#[cfg(feature = "objc2-core-foundation")]
32pub type NSRect = CGRect;
33
34// NS_ENUM
35#[repr(transparent)]
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
37pub struct NSRectEdge(pub NSUInteger);
38
39unsafe impl Encode for NSRectEdge {
40    const ENCODING: Encoding = NSUInteger::ENCODING;
41}
42
43unsafe impl RefEncode for NSRectEdge {
44    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
45}
46
47#[allow(non_upper_case_globals)]
48impl NSRectEdge {
49    #[doc(alias = "NSRectEdgeMinX")]
50    pub const MinX: Self = Self(0);
51    #[doc(alias = "NSRectEdgeMinY")]
52    pub const MinY: Self = Self(1);
53    #[doc(alias = "NSRectEdgeMaxX")]
54    pub const MaxX: Self = Self(2);
55    #[doc(alias = "NSRectEdgeMaxY")]
56    pub const MaxY: Self = Self(3);
57    pub const NSMinXEdge: Self = Self(NSRectEdge::MinX.0);
58    pub const NSMinYEdge: Self = Self(NSRectEdge::MinY.0);
59    pub const NSMaxXEdge: Self = Self(NSRectEdge::MaxX.0);
60    pub const NSMaxYEdge: Self = Self(NSRectEdge::MaxY.0);
61}
62
63#[cfg(test)]
64mod tests {
65    // We know the Rust implementation handles NaN, infinite, negative zero
66    // and so on properly, so let's ensure that NSEqualXXX handles these as
67    // well (so that we're confident that the implementations are equivalent).
68    #[test]
69    #[cfg(any(
70        all(target_vendor = "apple", target_os = "macos"), // or macabi
71        feature = "gnustep-1-7"
72    ))]
73    #[cfg(feature = "objc2-core-foundation")]
74    fn test_partial_eq() {
75        use super::*;
76        use crate::{NSEqualPoints, NSEqualRects, NSEqualSizes};
77        use objc2_core_foundation::CGFloat;
78
79        // We assume that comparisons handle e.g. `x` and `y` in the same way,
80        // therefore we set the coordinates / dimensions to the same.
81        let cases: &[(CGFloat, CGFloat)] = &[
82            (0.0, 0.0),
83            (-0.0, -0.0),
84            (0.0, -0.0),
85            (1.0, 1.0 + CGFloat::EPSILON),
86            (0.0, CGFloat::MIN_POSITIVE),
87            (0.0, CGFloat::EPSILON),
88            (1.0, 1.0),
89            (1.0, -1.0),
90            // Infinity
91            (CGFloat::INFINITY, CGFloat::INFINITY),
92            (CGFloat::INFINITY, CGFloat::NEG_INFINITY),
93            (CGFloat::NEG_INFINITY, CGFloat::NEG_INFINITY),
94            // NaN
95            (CGFloat::NAN, 0.0),
96            (CGFloat::NAN, 1.0),
97            (CGFloat::NAN, CGFloat::NAN),
98            (CGFloat::NAN, -CGFloat::NAN),
99            (-CGFloat::NAN, -CGFloat::NAN),
100            (CGFloat::NAN, CGFloat::INFINITY),
101        ];
102
103        for case in cases {
104            let point_a = NSPoint::new(case.0, case.1);
105            let point_b = NSPoint::new(case.0, case.1);
106            let actual = unsafe { NSEqualPoints(point_a, point_b) };
107            assert_eq!(point_a == point_b, actual);
108
109            if case.0 >= 0.0 && case.1 >= 0.0 {
110                let size_a = NSSize::new(case.0, case.1);
111                let size_b = NSSize::new(case.0, case.1);
112                let actual = unsafe { NSEqualSizes(size_a, size_b) };
113                assert_eq!(size_a == size_b, actual);
114
115                let rect_a = NSRect::new(point_a, size_a);
116                let rect_b = NSRect::new(point_b, size_b);
117                let actual = unsafe { NSEqualRects(rect_a, rect_b) };
118                assert_eq!(rect_a == rect_b, actual);
119            }
120        }
121    }
122}