objc2_foundation/
set.rs

1//! Utilities for the `NSSet` and `NSMutableSet` classes.
2use alloc::vec::Vec;
3#[cfg(feature = "NSEnumerator")]
4use core::fmt;
5
6use objc2::rc::{Retained, RetainedFromIterator};
7use objc2::{msg_send, AnyThread, Message};
8
9#[cfg(feature = "NSEnumerator")]
10use crate::iter;
11use crate::{util, NSMutableSet, NSSet};
12
13/// Convenience creation methods.
14impl<ObjectType: Message> NSSet<ObjectType> {
15    /// Creates an [`NSSet`] from a slice of `Retained`s.
16    ///
17    /// # Examples
18    ///
19    /// ```
20    /// use objc2_foundation::{NSSet, NSString};
21    ///
22    /// let strs = ["one", "two", "three"].map(NSString::from_str);
23    /// let set = NSSet::from_retained_slice(&strs);
24    /// ```
25    pub fn from_retained_slice(slice: &[Retained<ObjectType>]) -> Retained<Self> {
26        let len = slice.len();
27        let ptr = util::retained_ptr_cast_const(slice.as_ptr());
28        // SAFETY: Same as `NSArray::from_retained_slice`
29        unsafe { Self::initWithObjects_count(Self::alloc(), ptr, len) }
30    }
31
32    pub fn from_slice(slice: &[&ObjectType]) -> Retained<Self> {
33        let len = slice.len();
34        let ptr = util::ref_ptr_cast_const(slice.as_ptr());
35        // SAFETY: Same as `NSArray::from_slice`.
36        unsafe { Self::initWithObjects_count(Self::alloc(), ptr, len) }
37    }
38}
39
40/// Convenience creation methods.
41impl<ObjectType: Message> NSMutableSet<ObjectType> {
42    /// Creates an [`NSMutableSet`] from a slice of `Retained`s.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use objc2_foundation::{NSMutableSet, NSString};
48    ///
49    /// let strs = ["one", "two", "three"].map(NSString::from_str);
50    /// let set = NSMutableSet::from_retained_slice(&strs);
51    /// ```
52    pub fn from_retained_slice(slice: &[Retained<ObjectType>]) -> Retained<Self> {
53        let len = slice.len();
54        let ptr = util::retained_ptr_cast_const(slice.as_ptr());
55        // SAFETY: Same as `NSArray::from_retained_slice`
56        unsafe { Self::initWithObjects_count(Self::alloc(), ptr, len) }
57    }
58
59    pub fn from_slice(slice: &[&ObjectType]) -> Retained<Self> {
60        let len = slice.len();
61        let ptr = util::ref_ptr_cast_const(slice.as_ptr());
62        // SAFETY: Same as `NSArray::from_slice`.
63        unsafe { Self::initWithObjects_count(Self::alloc(), ptr, len) }
64    }
65}
66
67/// Direct, unsafe object accessors.
68///
69/// Foundation's collection types store their items in such a way that they
70/// can give out references to their data without having to autorelease it
71/// first, see [the docs][collections-own].
72///
73/// This means that we can more efficiently access the set's objects, but
74/// _only_ if the set isn't mutated via e.g. `NSMutableSet` methods while
75/// doing so - otherwise, we might end up accessing a deallocated object.
76///
77/// [collections-own]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW12
78impl<ObjectType: Message> NSSet<ObjectType> {
79    /// A direct reference to an arbitrary object in the set.
80    ///
81    /// Consider using the [`anyObject`](Self::anyObject) method instead,
82    /// unless you're seeing performance issues from the retaining.
83    ///
84    /// # Safety
85    ///
86    /// The set must not be mutated while the reference is live.
87    #[doc(alias = "anyObject")]
88    pub unsafe fn anyObject_unchecked(&self) -> Option<&ObjectType> {
89        // SAFETY: Upheld by caller.
90        unsafe { msg_send![self, anyObject] }
91    }
92
93    /// A direct reference the member that matches the given object.
94    ///
95    /// Consider using the [`member`](Self::member) method instead,
96    /// unless you're seeing performance issues from the retaining.
97    ///
98    /// # Safety
99    ///
100    /// The set must not be mutated while the returned reference is live.
101    #[doc(alias = "member:")]
102    pub unsafe fn member_unchecked(&self, object: &ObjectType) -> Option<&ObjectType> {
103        // SAFETY: Upheld by caller.
104        unsafe { msg_send![self, member: object] }
105    }
106
107    /// Iterate over the set in an arbitrary order without retaining the
108    /// elements.
109    ///
110    /// Consider using the [`iter`](Self::iter) method instead, unless you're
111    /// seeing performance issues from the retaining.
112    ///
113    /// # Safety
114    ///
115    /// The set must not be mutated for the lifetime of the iterator, or the
116    /// elements it returns.
117    #[cfg(feature = "NSEnumerator")]
118    #[doc(alias = "objectEnumerator")]
119    #[inline]
120    pub unsafe fn iter_unchecked(&self) -> IterUnchecked<'_, ObjectType> {
121        IterUnchecked(super::iter::IterUnchecked::new(self))
122    }
123}
124
125/// Various accessor methods.
126impl<ObjectType: Message> NSSet<ObjectType> {
127    /// Returns the number of elements in the set.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use objc2_foundation::{ns_string, NSSet};
133    ///
134    /// let strs = [ns_string!("one"), ns_string!("two"), ns_string!("three")];
135    /// let set = NSSet::from_slice(&strs);
136    /// assert_eq!(set.len(), 3);
137    /// ```
138    #[doc(alias = "count")]
139    pub fn len(&self) -> usize {
140        self.count()
141    }
142
143    /// Returns `true` if the set contains no elements.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use objc2_foundation::{NSSet, NSObject};
149    ///
150    /// let set = NSSet::<NSObject>::new();
151    /// assert!(set.is_empty());
152    /// ```
153    pub fn is_empty(&self) -> bool {
154        self.count() == 0
155    }
156
157    /// An iterator visiting all elements in arbitrary order.
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use objc2_foundation::{ns_string, NSSet};
163    ///
164    /// let set = NSSet::from_slice(&[ns_string!("one"), ns_string!("two"), ns_string!("three")]);
165    /// for s in set.iter() {
166    ///     println!("{s}");
167    /// }
168    /// ```
169    #[cfg(feature = "NSEnumerator")]
170    #[doc(alias = "objectEnumerator")]
171    #[inline]
172    pub fn iter(&self) -> Iter<'_, ObjectType> {
173        Iter(super::iter::Iter::new(self))
174    }
175
176    /// Returns a [`Vec`] containing the set's elements in arbitrary order.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// use objc2_foundation::{NSSet, NSString};
182    ///
183    /// let strs = [
184    ///     NSString::from_str("one"),
185    ///     NSString::from_str("two"),
186    ///     NSString::from_str("three"),
187    /// ];
188    /// let set = NSSet::from_retained_slice(&strs);
189    /// let vec = set.to_vec();
190    /// assert_eq!(vec.len(), 3);
191    /// ```
192    #[cfg(feature = "NSEnumerator")]
193    pub fn to_vec(&self) -> Vec<Retained<ObjectType>> {
194        self.iter().collect()
195    }
196}
197
198#[cfg(feature = "NSEnumerator")]
199unsafe impl<ObjectType: Message> iter::FastEnumerationHelper for NSSet<ObjectType> {
200    type Item = ObjectType;
201
202    #[inline]
203    fn maybe_len(&self) -> Option<usize> {
204        Some(self.len())
205    }
206}
207
208#[cfg(feature = "NSEnumerator")]
209unsafe impl<ObjectType: Message> iter::FastEnumerationHelper for NSMutableSet<ObjectType> {
210    type Item = ObjectType;
211
212    #[inline]
213    fn maybe_len(&self) -> Option<usize> {
214        Some(self.len())
215    }
216}
217
218/// An iterator over the items of a set.
219#[derive(Debug)]
220#[cfg(feature = "NSEnumerator")]
221pub struct Iter<'a, ObjectType: Message>(iter::Iter<'a, NSSet<ObjectType>>);
222
223#[cfg(feature = "NSEnumerator")]
224__impl_iter! {
225    impl<'a, ObjectType: Message> Iterator<Item = Retained<ObjectType>> for Iter<'a, ObjectType> { ... }
226}
227
228/// An unchecked iterator over the items of a set.
229#[derive(Debug)]
230#[cfg(feature = "NSEnumerator")]
231pub struct IterUnchecked<'a, ObjectType: Message>(iter::IterUnchecked<'a, NSSet<ObjectType>>);
232
233#[cfg(feature = "NSEnumerator")]
234__impl_iter! {
235    impl<'a, ObjectType: Message> Iterator<Item = &'a ObjectType> for IterUnchecked<'a, ObjectType> { ... }
236}
237
238/// An iterator over unretained items of a set.
239///
240/// # Safety
241///
242/// The set must not be mutated while this is alive.
243#[derive(Debug)]
244#[cfg(feature = "NSEnumerator")]
245pub struct IntoIter<ObjectType: Message>(iter::IntoIter<NSSet<ObjectType>>);
246
247#[cfg(feature = "NSEnumerator")]
248__impl_iter! {
249    impl<'a, ObjectType: Message> Iterator<Item = Retained<ObjectType>> for IntoIter<ObjectType> { ... }
250}
251
252#[cfg(feature = "NSEnumerator")]
253__impl_into_iter! {
254    impl<ObjectType: Message> IntoIterator for &NSSet<ObjectType> {
255        type IntoIter = Iter<'_, ObjectType>;
256    }
257
258    impl<ObjectType: Message> IntoIterator for &NSMutableSet<ObjectType> {
259        type IntoIter = Iter<'_, ObjectType>;
260    }
261
262    impl<ObjectType: Message> IntoIterator for Retained<NSSet<ObjectType>> {
263        #[uses(new)]
264        type IntoIter = IntoIter<ObjectType>;
265    }
266
267    impl<ObjectType: Message> IntoIterator for Retained<NSMutableSet<ObjectType>> {
268        #[uses(new_mutable)]
269        type IntoIter = IntoIter<ObjectType>;
270    }
271}
272
273#[cfg(feature = "NSEnumerator")]
274impl<ObjectType: fmt::Debug + Message> fmt::Debug for NSSet<ObjectType> {
275    #[inline]
276    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277        f.debug_set().entries(self).finish()
278    }
279}
280
281#[cfg(feature = "NSEnumerator")]
282impl<ObjectType: fmt::Debug + Message> fmt::Debug for NSMutableSet<ObjectType> {
283    #[inline]
284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285        fmt::Debug::fmt(&**self, f)
286    }
287}
288
289#[cfg(feature = "NSEnumerator")]
290impl<ObjectType: fmt::Debug + Message> fmt::Debug for crate::NSCountedSet<ObjectType> {
291    #[inline]
292    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293        fmt::Debug::fmt(&**self, f)
294    }
295}
296
297impl<ObjectType: Message> Extend<Retained<ObjectType>> for &NSMutableSet<ObjectType> {
298    fn extend<I: IntoIterator<Item = Retained<ObjectType>>>(&mut self, iter: I) {
299        iter.into_iter().for_each(move |item| {
300            self.addObject(&item);
301        });
302    }
303}
304
305impl<'a, ObjectType: Message> Extend<&'a ObjectType> for &NSMutableSet<ObjectType> {
306    fn extend<I: IntoIterator<Item = &'a ObjectType>>(&mut self, iter: I) {
307        iter.into_iter().for_each(move |item| {
308            self.addObject(item);
309        });
310    }
311}
312
313impl<'a, ObjectType: Message + 'a> RetainedFromIterator<&'a ObjectType> for NSSet<ObjectType> {
314    fn retained_from_iter<I: IntoIterator<Item = &'a ObjectType>>(iter: I) -> Retained<Self> {
315        let vec = Vec::from_iter(iter);
316        Self::from_slice(&vec)
317    }
318}
319
320impl<ObjectType: Message> RetainedFromIterator<Retained<ObjectType>> for NSSet<ObjectType> {
321    fn retained_from_iter<I: IntoIterator<Item = Retained<ObjectType>>>(iter: I) -> Retained<Self> {
322        let vec = Vec::from_iter(iter);
323        Self::from_retained_slice(&vec)
324    }
325}
326
327impl<'a, ObjectType: Message + 'a> RetainedFromIterator<&'a ObjectType>
328    for NSMutableSet<ObjectType>
329{
330    fn retained_from_iter<I: IntoIterator<Item = &'a ObjectType>>(iter: I) -> Retained<Self> {
331        // TODO: Is this, or is using `initWithCapacity` the most optimal?
332        let vec = Vec::from_iter(iter);
333        Self::from_slice(&vec)
334    }
335}
336
337impl<ObjectType: Message> RetainedFromIterator<Retained<ObjectType>> for NSMutableSet<ObjectType> {
338    fn retained_from_iter<I: IntoIterator<Item = Retained<ObjectType>>>(iter: I) -> Retained<Self> {
339        // TODO: Is this, or is using `initWithCapacity` the most optimal?
340        let vec = Vec::from_iter(iter);
341        Self::from_retained_slice(&vec)
342    }
343}