use objc2::encode::{Encode, Encoding, RefEncode};
use objc2::ffi::NSUInteger;
#[cfg(target_pointer_width = "64")]
type InnerFloat = f64;
#[cfg(not(target_pointer_width = "64"))]
type InnerFloat = f32;
pub type CGFloat = InnerFloat;
#[cfg(all(
feature = "apple",
not(all(target_os = "macos", target_pointer_width = "32"))
))]
mod names {
pub(super) const POINT: &str = "CGPoint";
pub(super) const SIZE: &str = "CGSize";
pub(super) const RECT: &str = "CGRect";
}
#[cfg(any(
feature = "gnustep-1-7",
all(target_os = "macos", target_pointer_width = "32")
))]
mod names {
pub(super) const POINT: &str = "_NSPoint";
pub(super) const SIZE: &str = "_NSSize";
pub(super) const RECT: &str = "_NSRect";
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct CGPoint {
pub x: CGFloat,
pub y: CGFloat,
}
unsafe impl Encode for CGPoint {
const ENCODING: Encoding =
Encoding::Struct(names::POINT, &[CGFloat::ENCODING, CGFloat::ENCODING]);
}
unsafe impl RefEncode for CGPoint {
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}
impl CGPoint {
#[inline]
#[doc(alias = "NSMakePoint")]
#[doc(alias = "CGPointMake")]
pub const fn new(x: CGFloat, y: CGFloat) -> Self {
Self { x, y }
}
#[doc(alias = "NSZeroPoint")]
#[doc(alias = "CGPointZero")]
#[doc(alias = "ORIGIN")]
pub const ZERO: Self = Self::new(0.0, 0.0);
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct CGSize {
pub width: CGFloat,
pub height: CGFloat,
}
unsafe impl Encode for CGSize {
const ENCODING: Encoding =
Encoding::Struct(names::SIZE, &[CGFloat::ENCODING, CGFloat::ENCODING]);
}
unsafe impl RefEncode for CGSize {
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}
impl CGSize {
#[inline]
#[doc(alias = "NSMakeSize")]
#[doc(alias = "CGSizeMake")]
pub const fn new(width: CGFloat, height: CGFloat) -> Self {
Self { width, height }
}
#[inline]
pub fn abs(self) -> Self {
Self::new(self.width.abs(), self.height.abs())
}
#[doc(alias = "NSZeroSize")]
#[doc(alias = "CGSizeZero")]
pub const ZERO: Self = Self::new(0.0, 0.0);
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct CGRect {
pub origin: CGPoint,
pub size: CGSize,
}
unsafe impl Encode for CGRect {
const ENCODING: Encoding =
Encoding::Struct(names::RECT, &[CGPoint::ENCODING, CGSize::ENCODING]);
}
unsafe impl RefEncode for CGRect {
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}
impl CGRect {
#[inline]
#[doc(alias = "NSMakeRect")]
#[doc(alias = "CGRectMake")]
pub const fn new(origin: CGPoint, size: CGSize) -> Self {
Self { origin, size }
}
#[doc(alias = "NSZeroRect")]
#[doc(alias = "CGRectZero")]
pub const ZERO: Self = Self::new(CGPoint::ZERO, CGSize::ZERO);
#[inline]
#[doc(alias = "CGRectStandardize")]
pub fn standardize(self) -> Self {
Self::new(self.origin, self.size.abs())
}
#[inline]
#[doc(alias = "CGRectGetMinX")]
#[doc(alias = "CGRectGetMinY")]
#[doc(alias = "NSMinX")]
#[doc(alias = "NSMinY")]
pub fn min(self) -> CGPoint {
self.origin
}
#[inline]
#[doc(alias = "CGRectGetMidX")]
#[doc(alias = "CGRectGetMidY")]
#[doc(alias = "NSMidX")]
#[doc(alias = "NSMidY")]
pub fn mid(self) -> CGPoint {
CGPoint::new(
self.origin.x + (self.size.width * 0.5),
self.origin.y + (self.size.height * 0.5),
)
}
#[inline]
#[doc(alias = "CGRectGetMaxX")]
#[doc(alias = "CGRectGetMaxY")]
#[doc(alias = "NSMaxX")]
#[doc(alias = "NSMaxY")]
pub fn max(self) -> CGPoint {
CGPoint::new(
self.origin.x + self.size.width,
self.origin.y + self.size.height,
)
}
#[inline]
#[doc(alias = "CGRectIsEmpty")]
pub fn is_empty(self) -> bool {
!(self.size.width > 0.0 && self.size.height > 0.0)
}
}
pub type NSPoint = CGPoint;
pub type NSSize = CGSize;
pub type NSRect = CGRect;
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NSRectEdge(pub NSUInteger);
unsafe impl Encode for NSRectEdge {
const ENCODING: Encoding = NSUInteger::ENCODING;
}
unsafe impl RefEncode for NSRectEdge {
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}
#[allow(non_upper_case_globals)]
impl NSRectEdge {
#[doc(alias = "NSRectEdgeMinX")]
pub const MinX: Self = Self(0);
#[doc(alias = "NSRectEdgeMinY")]
pub const MinY: Self = Self(1);
#[doc(alias = "NSRectEdgeMaxX")]
pub const MaxX: Self = Self(2);
#[doc(alias = "NSRectEdgeMaxY")]
pub const MaxY: Self = Self(3);
pub const NSMinXEdge: Self = Self(NSRectEdge::MinX.0);
pub const NSMinYEdge: Self = Self(NSRectEdge::MinY.0);
pub const NSMaxXEdge: Self = Self(NSRectEdge::MaxX.0);
pub const NSMaxYEdge: Self = Self(NSRectEdge::MaxY.0);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cgsize_new() {
CGSize::new(1.0, 1.0);
CGSize::new(0.0, -0.0);
CGSize::new(-0.0, 0.0);
CGSize::new(-0.0, -0.0);
CGSize::new(-1.0, -1.0);
CGSize::new(-1.0, 1.0);
CGSize::new(1.0, -1.0);
}
#[test]
#[cfg(any(all(feature = "apple", target_os = "macos"), feature = "gnustep-1-7"))] #[cfg(feature = "NSGeometry")]
fn test_partial_eq() {
use crate::Foundation::{NSEqualPoints, NSEqualRects, NSEqualSizes};
let cases: &[(CGFloat, CGFloat)] = &[
(0.0, 0.0),
(-0.0, -0.0),
(0.0, -0.0),
(1.0, 1.0 + CGFloat::EPSILON),
(0.0, CGFloat::MIN_POSITIVE),
(0.0, CGFloat::EPSILON),
(1.0, 1.0),
(1.0, -1.0),
(CGFloat::INFINITY, CGFloat::INFINITY),
(CGFloat::INFINITY, CGFloat::NEG_INFINITY),
(CGFloat::NEG_INFINITY, CGFloat::NEG_INFINITY),
(CGFloat::NAN, 0.0),
(CGFloat::NAN, 1.0),
(CGFloat::NAN, CGFloat::NAN),
(CGFloat::NAN, -CGFloat::NAN),
(-CGFloat::NAN, -CGFloat::NAN),
(CGFloat::NAN, CGFloat::INFINITY),
];
for case in cases {
let point_a = NSPoint::new(case.0, case.1);
let point_b = NSPoint::new(case.0, case.1);
let actual = unsafe { NSEqualPoints(point_a, point_b).as_bool() };
assert_eq!(point_a == point_b, actual);
if case.0 >= 0.0 && case.1 >= 0.0 {
let size_a = NSSize::new(case.0, case.1);
let size_b = NSSize::new(case.0, case.1);
let actual = unsafe { NSEqualSizes(size_a, size_b).as_bool() };
assert_eq!(size_a == size_b, actual);
let rect_a = NSRect::new(point_a, size_a);
let rect_b = NSRect::new(point_b, size_b);
let actual = unsafe { NSEqualRects(rect_a, rect_b).as_bool() };
assert_eq!(rect_a == rect_b, actual);
}
}
}
}