Skip to content
This repository was archived by the owner on Aug 29, 2022. It is now read-only.

Commit ab76283

Browse files
committed
Merge pull request #200 from bignerdranch/zwaldowski/swift-4
Move to Swift 4 minimum
2 parents 190f44e + 3fcee35 commit ab76283

35 files changed

+154
-257
lines changed

.swiftlint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
disabled_rules:
2+
- block_based_kvo
23
- nesting
34
- todo
45
opt_in_rules:

Configurations/Base.xcconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,4 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
8181
CLANG_ANALYZER_NONNULL = YES
8282

8383
// Swift Compiler - Version
84-
SWIFT_VERSION = 3.0
84+
SWIFT_VERSION = 4.0

Configurations/Framework.xcconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ PRODUCT_NAME = Deferred
3030

3131
// Swift Compiler - Custom Flags
3232
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) XCODE
33+
34+
// Swift Compiler - General
35+
SWIFT_INSTALL_OBJC_HEADER = NO

Deferred.xcodeproj/xcshareddata/xcschemes/Deferred.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
enableThreadSanitizer = "YES"
2930
codeCoverageEnabled = "YES"
3031
shouldUseLaunchSchemeArgsEnv = "YES">
3132
<Testables>

Deferred.xcodeproj/xcshareddata/xcschemes/MobileDeferred.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
enableThreadSanitizer = "YES"
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<Testables>
3132
<TestableReference

Deferred.xcodeproj/xcshareddata/xcschemes/TVDeferred.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
enableThreadSanitizer = "YES"
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<Testables>
3132
<TestableReference

Package.swift

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// swift-tools-version:4.0
2+
13
//
24
// Package.swift
35
// Deferred
@@ -10,18 +12,24 @@ import PackageDescription
1012

1113
let package = Package(
1214
name: "Deferred",
15+
products: [
16+
.library(name: "Deferred", type: .dynamic, targets: [ "Deferred", "Task" ])
17+
],
1318
targets: [
14-
Target(name: "Atomics"),
15-
Target(name: "Deferred", dependencies: [
16-
.Target(name: "Atomics")
17-
]),
18-
Target(name: "Task", dependencies: [
19-
.Target(name: "Deferred")
20-
])
21-
], exclude: [
22-
"Tests/AllTestsCommon.swift"
23-
]
24-
)
25-
26-
let dylib = Product(name: "Deferred", type: .Library(.Dynamic), modules: "Deferred", "Task")
27-
products.append(dylib)
19+
.target(name: "Atomics"),
20+
.target(
21+
name: "Deferred",
22+
dependencies: [ "Atomics" ]),
23+
.testTarget(
24+
name: "DeferredTests",
25+
dependencies: [ "Deferred" ],
26+
exclude: [ "Tests/AllTestsCommon.swift" ]),
27+
.target(
28+
name: "Task",
29+
dependencies: [ "Deferred" ]),
30+
.testTarget(
31+
name: "TaskTests",
32+
dependencies: [ "Deferred", "Task" ],
33+
exclude: [ "Tests/AllTestsCommon.swift" ])
34+
],
35+
swiftLanguageVersions: [ 4 ])

Sources/Deferred/Deferred.swift

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import Dispatch
1010

1111
#if SWIFT_PACKAGE
12-
import Atomics
12+
import Atomics
1313
#elseif XCODE
14-
import Deferred.Atomics
14+
import Deferred.Atomics
1515
#endif
1616

1717
/// A deferred is a value that may become determined (or "filled") at some point
@@ -40,7 +40,7 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
4040
/// Creates an instance resolved with `value`.
4141
public init(filledWith value: Value) {
4242
storage.withUnsafeMutablePointerToElements { (pointerToElement) in
43-
pointerToElement.initialize(to: Storage.box(value))
43+
pointerToElement.initialize(to: Storage.convertToReference(value))
4444
}
4545
}
4646

@@ -55,7 +55,8 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
5555
private func notify(flags: DispatchWorkItemFlags, upon queue: DispatchQueue, execute body: @escaping(Value) -> Void) {
5656
group.notify(flags: flags, queue: queue) { [storage] in
5757
guard let ptr = storage.withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .none) }) else { return }
58-
body(Storage.unbox(from: ptr))
58+
let reference = Unmanaged<AnyObject>.fromOpaque(ptr).takeUnretainedValue()
59+
body(Storage.convertFromReference(reference))
5960
}
6061
}
6162

@@ -81,7 +82,8 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
8182
guard case .success = group.wait(timeout: time),
8283
let ptr = storage.withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .none) }) else { return nil }
8384

84-
return Storage.unbox(from: ptr)
85+
let reference = Unmanaged<AnyObject>.fromOpaque(ptr).takeUnretainedValue()
86+
return Storage.convertFromReference(reference)
8587
}
8688

8789
// MARK: PromiseProtocol
@@ -94,7 +96,7 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
9496

9597
@discardableResult
9698
public func fill(with value: Value) -> Bool {
97-
let box = Storage.box(value)
99+
let box = Unmanaged.passRetained(Storage.convertToReference(value))
98100

99101
let wonRace = storage.withAtomicPointerToElement {
100102
bnr_atomic_ptr_compare_and_swap($0, nil, box.toOpaque(), .thread)
@@ -110,29 +112,16 @@ public final class Deferred<Value>: FutureProtocol, PromiseProtocol {
110112
}
111113
}
112114

113-
#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
114-
private typealias DeferredRaw<T> = Unmanaged<AnyObject>
115-
#else
116-
// In order to assign the value of a scalar in a Deferred using atomics, we must
117-
// box it up into something word-sized. See `atomicInitialize` above.
118-
private final class Box<T> {
119-
let contents: T
115+
private final class DeferredStorage<Value>: ManagedBuffer<Void, AnyObject?> {
120116

121-
init(_ contents: T) {
122-
self.contents = contents
117+
static func create() -> DeferredStorage<Value> {
118+
return unsafeDowncast(super.create(minimumCapacity: 1, makingHeaderWith: { _ in }), to: DeferredStorage<Value>.self)
123119
}
124-
}
125-
126-
private typealias DeferredRaw<T> = Unmanaged<Box<T>>
127-
#endif
128-
129-
private final class DeferredStorage<Value>: ManagedBuffer<Void, DeferredRaw<Value>?> {
130120

131-
typealias _Self = DeferredStorage<Value>
132-
typealias Element = DeferredRaw<Value>
133-
134-
static func create() -> _Self {
135-
return unsafeDowncast(super.create(minimumCapacity: 1, makingHeaderWith: { _ in }), to: _Self.self)
121+
deinit {
122+
_ = withUnsafeMutablePointers { (_, pointerToReference) in
123+
pointerToReference.deinitialize(count: 1)
124+
}
136125
}
137126

138127
func withAtomicPointerToElement<Return>(_ body: (UnsafeMutablePointer<UnsafeAtomicRawPointer>) throws -> Return) rethrows -> Return {
@@ -141,28 +130,33 @@ private final class DeferredStorage<Value>: ManagedBuffer<Void, DeferredRaw<Valu
141130
}
142131
}
143132

144-
deinit {
145-
guard let ptr = withAtomicPointerToElement({ bnr_atomic_ptr_load($0, .global) }) else { return }
146-
Element.fromOpaque(ptr).release()
147-
}
148-
149-
static func unbox(from ptr: UnsafeMutableRawPointer) -> Value {
150-
let raw = Element.fromOpaque(ptr)
151-
#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
133+
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
134+
static func convertFromReference(_ value: AnyObject) -> Value {
152135
// Contract of using box(_:) counterpart
153136
// swiftlint:disable:next force_cast
154-
return raw.takeUnretainedValue() as! Value
155-
#else
156-
return raw.takeUnretainedValue().contents
157-
#endif
137+
return value as! Value
138+
}
139+
140+
static func convertToReference(_ value: Value) -> AnyObject {
141+
return value as AnyObject
142+
}
143+
#else
144+
// In order to assign the value in a Deferred using atomics, we must
145+
// box it up into something word-sized. See `fill(with:)` above.
146+
private final class Box {
147+
let wrapped: Value
148+
init(_ wrapped: Value) {
149+
self.wrapped = wrapped
150+
}
151+
}
152+
153+
static func convertToReference(_ value: Value) -> AnyObject {
154+
return Box(value)
158155
}
159156

160-
static func box(_ value: Value) -> Element {
161-
#if swift(>=3.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
162-
return Unmanaged.passRetained(value as AnyObject)
163-
#else
164-
return Unmanaged.passRetained(Box(value))
165-
#endif
157+
static func convertFromReference(_ value: AnyObject) -> Value {
158+
return unsafeDowncast(value, to: Box.self).wrapped
166159
}
160+
#endif
167161

168162
}

Sources/Deferred/Executor.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import Dispatch
1010
import Foundation
1111
#if !os(macOS) && !os(iOS) && !os(tvOS) && !os(watchOS)
12-
import CoreFoundation
12+
import CoreFoundation
1313
#endif
1414

1515
/// An executor calls closures submitted to it, typically in first-in, first-out
@@ -127,9 +127,9 @@ extension OperationQueue: Executor {
127127
extension CFRunLoop: Executor {
128128
@nonobjc public func submit(_ body: @escaping() -> Void) {
129129
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
130-
CFRunLoopPerformBlock(self, CFRunLoopMode.defaultMode.rawValue, body)
130+
CFRunLoopPerformBlock(self, CFRunLoopMode.defaultMode.rawValue, body)
131131
#else
132-
CFRunLoopPerformBlock(self, kCFRunLoopDefaultMode, body)
132+
CFRunLoopPerformBlock(self, kCFRunLoopDefaultMode, body)
133133
#endif
134134
CFRunLoopWakeUp(self)
135135
}

Sources/Deferred/FutureComposition.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Dispatch
1010

1111
// swiftlint:disable force_cast
1212
// swiftlint:disable function_parameter_count
13+
// swiftlint:disable large_tuple
1314
// swiftlint:disable line_length
1415
// We darn well know what unholiness we are pulling
1516

@@ -123,7 +124,3 @@ extension FutureProtocol {
123124
}
124125
}
125126
}
126-
127-
// swiftlint:enable line_length
128-
// swiftlint:enable function_parameter_count
129-
// swiftlint:enable force_cast

0 commit comments

Comments
 (0)