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
//! 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 downgraded 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 they can upgraded to an `Id` in a manner that
//! safely fails 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(apple, doc = "```")]
#![cfg_attr(not(apple), doc = "```no_run")]
//! use objc2::{class, msg_send};
//! use objc2::rc::{autoreleasepool, Id, Shared, WeakId};
//! use objc2::runtime::Object;
//!
//! // Id will release the object when dropped
//! let obj: Id<Object, Shared> = unsafe {
//!     Id::new(msg_send![class!(NSObject), new])
//! };
//!
//! // 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 autorelease;
mod id;
mod id_forwarding_impls;
mod id_traits;
mod ownership;
mod weak_id;

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)]
mod tests {
    use core::mem::size_of;

    use super::{Id, Owned, Shared, WeakId};

    struct TestType {
        _data: [u8; 0], // TODO: `UnsafeCell`?
    }

    #[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 ()>()
        );
    }
}