Skip to main content

mtl_foundation/
array.rs

1//! Array type for Foundation.
2//!
3//! Corresponds to `Foundation/NSArray.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! class Array : public Copying<Array> {
10//! public:
11//!     static Array* array();
12//!     static Array* array(const Object* pObject);
13//!     static Array* array(const Object* const* pObjects, UInteger count);
14//!     static Array* alloc();
15//!     Array*        init();
16//!     Array*        init(const Object* const* pObjects, UInteger count);
17//!     Array*        init(const class Coder* pCoder);
18//!     template <class _Object = Object>
19//!     _Object*            object(UInteger index) const;
20//!     UInteger            count() const;
21//!     Enumerator<Object>* objectEnumerator() const;
22//! };
23//! }
24//! ```
25
26use std::ffi::c_void;
27use std::marker::PhantomData;
28use std::ptr::NonNull;
29
30use mtl_sys::{class, msg_send_0, msg_send_1, msg_send_2, sel};
31
32use crate::enumerator::Enumerator;
33use crate::object::{Copying, Object, Referencing};
34use crate::types::UInteger;
35
36/// An Objective-C array object.
37///
38/// C++ equivalent: `NS::Array`
39#[repr(transparent)]
40pub struct Array<T = Object> {
41    inner: NonNull<c_void>,
42    _marker: PhantomData<T>,
43}
44
45impl<T> Clone for Array<T> {
46    fn clone(&self) -> Self {
47        Self {
48            inner: self.inner,
49            _marker: PhantomData,
50        }
51    }
52}
53
54impl<T> Array<T> {
55    /// Create an empty array.
56    ///
57    /// C++ equivalent: `static Array* array()`
58    #[inline]
59    pub fn array() -> Option<Self> {
60        unsafe {
61            let ptr: *mut c_void = msg_send_0(class!(NSArray).as_ptr(), sel!(array));
62            Self::from_ptr(ptr)
63        }
64    }
65
66    /// Create an array with a single object.
67    ///
68    /// C++ equivalent: `static Array* array(const Object* pObject)`
69    #[inline]
70    pub fn array_with_object(object: *const T) -> Option<Self> {
71        unsafe {
72            let ptr: *mut c_void =
73                msg_send_1(class!(NSArray).as_ptr(), sel!(arrayWithObject:), object);
74            Self::from_ptr(ptr)
75        }
76    }
77
78    /// Create an array with multiple objects.
79    ///
80    /// C++ equivalent: `static Array* array(const Object* const* pObjects, UInteger count)`
81    #[inline]
82    pub fn array_with_objects(objects: *const *const T, count: UInteger) -> Option<Self> {
83        unsafe {
84            let ptr: *mut c_void = msg_send_2(
85                class!(NSArray).as_ptr(),
86                sel!(arrayWithObjects:count:),
87                objects,
88                count,
89            );
90            Self::from_ptr(ptr)
91        }
92    }
93
94    /// Allocate a new array.
95    ///
96    /// C++ equivalent: `static Array* alloc()`
97    #[inline]
98    pub fn alloc() -> Option<Self> {
99        unsafe {
100            let ptr: *mut c_void = msg_send_0(class!(NSArray).as_ptr(), sel!(alloc));
101            Self::from_ptr(ptr)
102        }
103    }
104
105    /// Initialize an allocated array.
106    ///
107    /// C++ equivalent: `Array* init()`
108    #[inline]
109    pub fn init(&self) -> Option<Self> {
110        unsafe {
111            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
112            Self::from_ptr(ptr)
113        }
114    }
115
116    /// Initialize with multiple objects.
117    ///
118    /// C++ equivalent: `Array* init(const Object* const* pObjects, UInteger count)`
119    #[inline]
120    pub fn init_with_objects(&self, objects: *const *const T, count: UInteger) -> Option<Self> {
121        unsafe {
122            let ptr: *mut c_void =
123                msg_send_2(self.as_ptr(), sel!(initWithObjects:count:), objects, count);
124            Self::from_ptr(ptr)
125        }
126    }
127
128    /// Initialize with a coder.
129    ///
130    /// C++ equivalent: `Array* init(const class Coder* pCoder)`
131    #[inline]
132    pub fn init_with_coder(&self, coder: *const c_void) -> Option<Self> {
133        unsafe {
134            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithCoder:), coder);
135            Self::from_ptr(ptr)
136        }
137    }
138
139    /// Get the object at the specified index.
140    ///
141    /// C++ equivalent: `template <class _Object = Object> _Object* object(UInteger index) const`
142    #[inline]
143    pub fn object(&self, index: UInteger) -> *mut T {
144        unsafe { msg_send_1(self.as_ptr(), sel!(objectAtIndex:), index) }
145    }
146
147    /// Get the count of objects in the array.
148    ///
149    /// C++ equivalent: `UInteger count() const`
150    #[inline]
151    pub fn count(&self) -> UInteger {
152        unsafe { msg_send_0(self.as_ptr(), sel!(count)) }
153    }
154
155    /// Get an enumerator for the objects in the array.
156    ///
157    /// C++ equivalent: `Enumerator<Object>* objectEnumerator() const`
158    #[inline]
159    pub fn object_enumerator(&self) -> Option<Enumerator<T>> {
160        unsafe {
161            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(objectEnumerator));
162            Enumerator::from_ptr(ptr)
163        }
164    }
165
166    /// Create an Array from a raw pointer.
167    ///
168    /// # Safety
169    ///
170    /// The pointer must be a valid Objective-C NSArray object.
171    #[inline]
172    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
173        NonNull::new(ptr).map(|inner| Self {
174            inner,
175            _marker: PhantomData,
176        })
177    }
178}
179
180impl<T> Referencing for Array<T> {
181    #[inline]
182    fn as_ptr(&self) -> *const c_void {
183        self.inner.as_ptr()
184    }
185}
186
187impl<T> Copying for Array<T> {
188    #[inline]
189    fn copy(&self) -> Option<Self> {
190        unsafe {
191            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
192            Self::from_ptr(ptr)
193        }
194    }
195}
196
197// SAFETY: NSArray is thread-safe for reference counting
198unsafe impl<T: Send> Send for Array<T> {}
199unsafe impl<T: Sync> Sync for Array<T> {}
200
201impl<T> std::fmt::Debug for Array<T> {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        f.debug_struct("Array")
204            .field("ptr", &self.inner)
205            .field("count", &self.count())
206            .finish()
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[test]
215    fn test_array_size() {
216        // Array should be pointer-sized
217        assert_eq!(
218            std::mem::size_of::<Array<Object>>(),
219            std::mem::size_of::<*mut c_void>()
220        );
221    }
222}