1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Utilities for reference counting Objective-C objects.
//!
//! These utilities in this module provide ARC-like semantics for working with
//! Objective-C's reference counted objects.
//!
//! A smart pointer [`Id`] is provided to ensure that Objective-C objects are
//! retained and released when created and dropped, respectively.
//!
//! To enforce aliasing rules, an `Id` can be either owned or shared; if it is
//! owned, meaning the `Id` is the only reference to the object, it can be
//! mutably dereferenced. An owned `Id` can be converted to a shared `Id`,
//! which can be cloned to allow multiple references.
//!
//! Weak references may be created using the [`WeakId`] struct; these will not
//! retain the object, but one can attempt to load them and obtain an `Id`, or
//! safely fail if the object has been deallocated.
//!
//! See [the clang documentation][clang-arc] and [the Apple article on memory
//! management][mem-mgmt] (similar document exists [for Core Foundation][cf])
//! for more information on automatic and manual reference counting.
//!
//! It can also be useful to [enable Malloc Debugging][mem-debug] if you're trying
//! to figure out if/where your application has memory errors and leaks.
//!
//! [clang-arc]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html
//! [mem-mgmt]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
//! [cf]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/CFMemoryMgmt.html
//! [mem-debug]: https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html
//!
//!
//! ## Example
//!
#![cfg_attr(feature = "apple", doc = "```")]
#![cfg_attr(not(feature = "apple"), doc = "```no_run")]
//! use objc2::{class, msg_send_id};
//! use objc2::rc::{autoreleasepool, Id, Shared, WeakId};
//! use objc2::runtime::Object;
//!
//! // Id will release the object when dropped
//! let obj: Id<Object, Shared> = unsafe {
//!     msg_send_id![class!(NSObject), new].unwrap()
//! };
//!
//! // Cloning retains the object an additional time
//! let cloned = obj.clone();
//! autoreleasepool(|pool| {
//!     // Autorelease consumes the Id, but won't
//!     // actually release until the end of an autoreleasepool
//!     let obj_ref: &Object = cloned.autorelease(pool);
//! });
//!
//! // Weak references won't retain the object
//! let weak = WeakId::new(&obj);
//! drop(obj);
//! assert!(weak.load().is_none());
//! ```

mod allocated;
mod autorelease;
mod id;
mod id_forwarding_impls;
mod id_traits;
mod ownership;
mod weak_id;

#[cfg(test)]
mod test_object;

pub use self::allocated::Allocated;
pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe};
pub use self::id::Id;
pub use self::id_traits::{DefaultId, SliceId, SliceIdMut};
pub use self::ownership::{Owned, Ownership, Shared};
pub use self::weak_id::WeakId;

#[cfg(test)]
pub(crate) use self::test_object::{RcTestObject, ThreadTestData};

#[cfg(test)]
mod tests {
    use core::marker::PhantomData;
    use core::mem::size_of;

    use super::{Id, Owned, Ownership, Shared, WeakId};
    use crate::runtime::Object;

    #[repr(C)]
    struct TestType {
        inner: Object,
    }

    #[repr(C)]
    struct MyObject<'a> {
        inner: Object,
        p: PhantomData<&'a str>,
    }

    /// Test that `Id<T, O>` is covariant over `T`.
    #[allow(unused)]
    fn assert_id_variance<'a, 'b, O: Ownership>(
        obj: &'a Id<MyObject<'static>, O>,
    ) -> &'a Id<MyObject<'b>, O> {
        obj
    }

    /// Test that `WeakId<T>` is covariant over `T`.
    #[allow(unused)]
    fn assert_weak_id_variance<'a, 'b>(
        obj: &'a WeakId<MyObject<'static>>,
    ) -> &'a WeakId<MyObject<'b>> {
        obj
    }

    #[test]
    fn test_size_of() {
        assert_eq!(size_of::<Id<TestType, Owned>>(), size_of::<&TestType>());
        assert_eq!(size_of::<Id<TestType, Shared>>(), size_of::<&TestType>());
        assert_eq!(
            size_of::<Option<Id<TestType, Owned>>>(),
            size_of::<&TestType>()
        );
        assert_eq!(
            size_of::<Option<Id<TestType, Shared>>>(),
            size_of::<&TestType>()
        );

        assert_eq!(
            size_of::<Option<WeakId<TestType>>>(),
            size_of::<*const ()>()
        );
    }
}