Created
May 15, 2020 13:32
-
-
Save dabrahams/d748df73c49f769cbddff007475ff8e0 to your computer and use it in GitHub Desktop.
Rescued very old proposal to redesign Unmanaged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #if false | |
| Changes to Unmanaged | |
| -public struct Unmanaged<Instance : AnyObject> { | |
| // New API: `UnsafeReference(bitPattern:)`. | |
| - public static func fromOpaque(value: COpaquePointer) -> Unmanaged | |
| // New API: `OpaquePointer(bitPattern:)`. | |
| - public func toOpaque() -> COpaquePointer | |
| // New API: `UnsafeReference(retaining:)`. | |
| - public static func passRetained(value: Instance) -> Unmanaged | |
| // New API: `UnsafeReference(withoutRetaining:)`. | |
| - public static func passUnretained(value: Instance) -> Unmanaged | |
| // New API: `UnsafeReference.object`. | |
| - public func takeUnretainedValue() -> Instance | |
| // New API: `UnsafeReference.release()`. | |
| - public func takeRetainedValue() -> Instance | |
| // New API: none. | |
| - public func retain() -> Unmanaged | |
| - public func release() | |
| - public func autorelease() -> Unmanaged | |
| -} | |
| #endif | |
| /// Holds an instance of `Object`, carrying ownership semantics that | |
| /// are not known to the type system and not represented in memory. | |
| /// | |
| /// `UnsafeReference<T>` appears as a return type or "out" parameter | |
| /// in [Core | |
| /// Foundation](https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CoreFoundation_Collection/) | |
| /// APIs that have not been | |
| /// [annotated](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID79) | |
| /// with information that allows clients to receive a safe `T` | |
| /// directly. | |
| /// | |
| /// An `UnsafeReference` instance `u` can be in one of three | |
| /// "ownership states": | |
| /// | |
| /// 1. **Unretained**, where `u.object` yields a valid `T` and will | |
| /// do so through any number of accesses to the `.object` | |
| /// properties of `UnsafeReference` instances. The behavior of | |
| /// `u.release()` is undefined, and any other operations may cause | |
| /// `u` to transition to the *released* state. | |
| /// | |
| /// 2. **Retained**, where `u.release()` yields a valid `T` and will | |
| /// do so exactly once. Calling `.release()` transitions `u` and | |
| /// all its copies to the *released* state. | |
| /// | |
| /// 3. **Released**, where the behavior of both `u.object` and | |
| /// `u.release()` is undefined. A released `UnsafeReference` | |
| /// can't be used for anything. | |
| /// | |
| /// The ownership state of an `UnsafeReference` is not | |
| /// programmatically detectable, so careful documentation is | |
| /// essential. When an `UnsafeReference` is returned in the | |
| /// *retained* state, it is usual to document that "the caller is | |
| /// responsible for releasing the object" or that the API "follows | |
| /// the [create | |
| /// rule](https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/writerid/cfCreateRule)." | |
| /// Other `UnsafeReferences` are assumed to be in the *unretained* | |
| /// state. No API should pass or return a *released* | |
| /// `UnsafeReference` | |
| /// | |
| /// The safest way to deal with an instance of `UnsafeReference<T>` is | |
| /// to immediately extract a safe `T` from it exactly once (via | |
| /// `.object` or `.release()` according to its state), and let it go | |
| /// out of scope. | |
| /// | |
| /// In the common case where the `UnsafeReference` is a return value, | |
| /// it's best to do the extraction as part of the call, e.g.: | |
| /// ~~~~ | |
| /// let names: CFArray = CFHostGetNames(host).object | |
| /// let url: CFURL = CFHTTPMessageCopyRequestURL(message).release() | |
| /// ~~~ | |
| /// | |
| /// When the `UnsafeReference` is an "out" parameter, you can limit | |
| /// its scope by creating and unwrapping it in a closure: | |
| /// ~~~~ | |
| /// var properties: CFPropertyList = try { | |
| /// var properties: UnsafeReference<CFPropertyList>? | |
| /// let error = MIDIObjectGetProperties(midiClient, &properties, true) | |
| /// if error != noErr { | |
| /// throw NSError(domain: "midi", code: Int(error), userInfo: nil) | |
| /// } | |
| /// return properties!.object | |
| /// }() | |
| /// ~~~~ | |
| public struct UnsafeReference<Object : AnyObject> { | |
| /// Relinquishes ownership of the `Object` and returns it as a safe | |
| /// reference. | |
| /// | |
| /// - Requires: `self` is in the *retained* state. | |
| /// | |
| /// - Postcondition: `self` and all its copies are in the *released* state. | |
| /// | |
| /// - Warning: Calling `.release()` on an *unretained* or *released* | |
| /// `UnsafeReference` is a severe programming error yielding | |
| /// undefined behavior. | |
| /// | |
| /// - Warning: After this method is invoked once, invoking any | |
| /// methods on the same instance, or a copy thereof, is a severe | |
| /// programming error yielding undefined behavior. | |
| public func release() -> Object | |
| /// A safe reference to the `Object` instance. | |
| /// | |
| /// - Warning: if `self` is in the *retained* state, you must | |
| /// eventually call `.release()`, or the resulting object will be | |
| /// leaked. It's better to just capture the result of invoking | |
| /// `.release()` in that case. | |
| public var object: Object | |
| /// Creates an unsafe holder of `safeObject` in the *unretained* | |
| /// state; the held object can be accessed via the `.object` property. | |
| public init(withoutRetaining safeObject: Object) | |
| /// Creates an unsafe holder of `safeObject` in the *retained* | |
| /// state; the held object can be accessed via the `release()` | |
| /// method. | |
| public init(retaining safeObject: Object) | |
| /// Creates an unsafe holder of an object having the given | |
| /// `bitPattern`. | |
| public init(bitPattern: OpaquePointer) | |
| } | |
| extension OpaquePointer { | |
| /// Unsafely convert an unmanaged class reference to an opaque | |
| /// C pointer. | |
| /// | |
| /// This operation does not change reference counts. | |
| /// | |
| /// let str0: CFString = "boxcar" | |
| /// let bits = OpaquePointer(bitPattern: UnsafeReference(withoutRetaining: str0)) | |
| /// let str1 = UnsafeReference<CFString>(bitPattern: bits).object | |
| public init<T>(bitPattern bits: UnsafeReference<T>) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment