Skip to content

Commit 946f469

Browse files
committed
Swift 5/.6
1 parent b8afad2 commit 946f469

File tree

2 files changed

+175
-96
lines changed

2 files changed

+175
-96
lines changed

Sources/Mutex.swift

Lines changed: 6 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
// SOFTWARE.
3030
//
3131

32-
#if compiler(>=6) && !canImport(WinSDK)
32+
#if compiler(>=6)
33+
34+
#if !canImport(WinSDK)
3335

3436
// Backports the Swift 6 type Mutex<Value> to all Darwin platforms
3537

@@ -62,7 +64,7 @@ public struct Mutex<Value: ~Copyable>: @unchecked Sendable, ~Copyable {
6264
}
6365
}
6466

65-
#elseif compiler(>=6) && canImport(WinSDK)
67+
#else
6668

6769
// Windows doesn't support ~Copyable yet
6870

@@ -90,34 +92,6 @@ public struct Mutex<Value>: @unchecked Sendable {
9092
}
9193
}
9294

93-
#else
94-
95-
// Use Swift 5 compatible version
96-
97-
public struct Mutex<Value>: @unchecked Sendable {
98-
let storage: Storage<Value>
99-
100-
public init(_ initialValue: Value) {
101-
self.storage = Storage(initialValue)
102-
}
103-
104-
public borrowing func withLock<Result>(
105-
_ body: (inout Value) throws -> Result
106-
) rethrows -> Result {
107-
storage.lock()
108-
defer { storage.unlock() }
109-
return try body(&storage.value)
110-
}
111-
112-
public borrowing func withLockIfAvailable<Result>(
113-
_ body: (inout Value) throws -> Result
114-
) rethrows -> Result? {
115-
guard storage.tryLock() else { return nil }
116-
defer { storage.unlock() }
117-
return try body(&storage.value)
118-
}
119-
}
120-
12195
#endif
12296

12397
#if canImport(Darwin)
@@ -128,7 +102,6 @@ import func os.os_unfair_lock_lock
128102
import func os.os_unfair_lock_unlock
129103
import func os.os_unfair_lock_trylock
130104

131-
#if compiler(>=6.0)
132105
final class Storage<ValueA: ~Copyable> {
133106
private let _lock: os_unfair_lock_t
134107
var value: ValueA
@@ -156,35 +129,6 @@ final class Storage<ValueA: ~Copyable> {
156129
self._lock.deallocate()
157130
}
158131
}
159-
#else
160-
final class Storage<ValueB> {
161-
private let _lock: os_unfair_lock_t
162-
var value: ValueB
163-
164-
init(_ initialValue: consuming ValueB) {
165-
self._lock = .allocate(capacity: 1)
166-
self._lock.initialize(to: os_unfair_lock())
167-
self.value = initialValue
168-
}
169-
170-
func lock() {
171-
os_unfair_lock_lock(_lock)
172-
}
173-
174-
func unlock() {
175-
os_unfair_lock_unlock(_lock)
176-
}
177-
178-
func tryLock() -> Bool {
179-
os_unfair_lock_trylock(_lock)
180-
}
181-
182-
deinit {
183-
self._lock.deinitialize(count: 1)
184-
self._lock.deallocate()
185-
}
186-
}
187-
#endif
188132

189133
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
190134

@@ -196,7 +140,6 @@ import Android
196140
import Glibc
197141
#endif
198142

199-
#if compiler(>=6.0)
200143
final class Storage<ValueC: ~Copyable> {
201144
private let _lock: UnsafeMutablePointer<pthread_mutex_t>
202145

@@ -231,41 +174,6 @@ final class Storage<ValueC: ~Copyable> {
231174
self._lock.deallocate()
232175
}
233176
}
234-
#else
235-
final class Storage<ValueD> {
236-
private let _lock: UnsafeMutablePointer<pthread_mutex_t>
237-
var value: ValueD
238-
239-
init(_ initialValue: consuming ValueD) {
240-
var attr = pthread_mutexattr_t()
241-
pthread_mutexattr_init(&attr)
242-
self._lock = .allocate(capacity: 1)
243-
let err = pthread_mutex_init(self._lock, &attr)
244-
precondition(err == 0, "pthread_mutex_init error: \(err)")
245-
self.value = initialValue
246-
}
247-
248-
func lock() {
249-
let err = pthread_mutex_lock(_lock)
250-
precondition(err == 0, "pthread_mutex_lock error: \(err)")
251-
}
252-
253-
func unlock() {
254-
let err = pthread_mutex_unlock(_lock)
255-
precondition(err == 0, "pthread_mutex_unlock error: \(err)")
256-
}
257-
258-
func tryLock() -> Bool {
259-
pthread_mutex_trylock(_lock) == 0
260-
}
261-
262-
deinit {
263-
let err = pthread_mutex_destroy(self._lock)
264-
precondition(err == 0, "pthread_mutex_destroy error: \(err)")
265-
self._lock.deallocate()
266-
}
267-
}
268-
#endif
269177

270178
#elseif canImport(WinSDK)
271179

@@ -297,3 +205,5 @@ final class Storage<ValueF> {
297205
}
298206

299207
#endif
208+
209+
#endif

Sources/MutexSwift5.swift

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//
2+
// MutexSwift5.swift
3+
// swift-mutex
4+
//
5+
// Created by Simon Whitty on 03/06/2025.
6+
// Copyright 2025 Simon Whitty
7+
//
8+
// Distributed under the permissive MIT license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/swift-mutex
12+
//
13+
// Permission is hereby granted, free of charge, to any person obtaining a copy
14+
// of this software and associated documentation files (the "Software"), to deal
15+
// in the Software without restriction, including without limitation the rights
16+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
// copies of the Software, and to permit persons to whom the Software is
18+
// furnished to do so, subject to the following conditions:
19+
//
20+
// The above copyright notice and this permission notice shall be included in all
21+
// copies or substantial portions of the Software.
22+
//
23+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
// SOFTWARE.
30+
//
31+
32+
#if compiler(<6)
33+
34+
// Backports the Swift 6 type Mutex<Value> to Swift 5
35+
36+
public struct Mutex<Value>: @unchecked Sendable {
37+
let storage: Storage<Value>
38+
39+
public init(_ initialValue: Value) {
40+
self.storage = Storage(initialValue)
41+
}
42+
43+
public borrowing func withLock<Result>(
44+
_ body: (inout Value) throws -> Result
45+
) rethrows -> Result {
46+
storage.lock()
47+
defer { storage.unlock() }
48+
return try body(&storage.value)
49+
}
50+
51+
public borrowing func withLockIfAvailable<Result>(
52+
_ body: (inout Value) throws -> Result
53+
) rethrows -> Result? {
54+
guard storage.tryLock() else { return nil }
55+
defer { storage.unlock() }
56+
return try body(&storage.value)
57+
}
58+
}
59+
60+
#if canImport(Darwin)
61+
62+
import struct os.os_unfair_lock_t
63+
import struct os.os_unfair_lock
64+
import func os.os_unfair_lock_lock
65+
import func os.os_unfair_lock_unlock
66+
import func os.os_unfair_lock_trylock
67+
68+
final class Storage<ValueB> {
69+
private let _lock: os_unfair_lock_t
70+
var value: ValueB
71+
72+
init(_ initialValue: consuming ValueB) {
73+
self._lock = .allocate(capacity: 1)
74+
self._lock.initialize(to: os_unfair_lock())
75+
self.value = initialValue
76+
}
77+
78+
func lock() {
79+
os_unfair_lock_lock(_lock)
80+
}
81+
82+
func unlock() {
83+
os_unfair_lock_unlock(_lock)
84+
}
85+
86+
func tryLock() -> Bool {
87+
os_unfair_lock_trylock(_lock)
88+
}
89+
90+
deinit {
91+
self._lock.deinitialize(count: 1)
92+
self._lock.deallocate()
93+
}
94+
}
95+
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
96+
97+
#if canImport(Musl)
98+
import Musl
99+
#elseif canImport(Bionic)
100+
import Android
101+
#else
102+
import Glibc
103+
#endif
104+
105+
final class Storage<ValueD> {
106+
private let _lock: UnsafeMutablePointer<pthread_mutex_t>
107+
var value: ValueD
108+
109+
init(_ initialValue: consuming ValueD) {
110+
var attr = pthread_mutexattr_t()
111+
pthread_mutexattr_init(&attr)
112+
self._lock = .allocate(capacity: 1)
113+
let err = pthread_mutex_init(self._lock, &attr)
114+
precondition(err == 0, "pthread_mutex_init error: \(err)")
115+
self.value = initialValue
116+
}
117+
118+
func lock() {
119+
let err = pthread_mutex_lock(_lock)
120+
precondition(err == 0, "pthread_mutex_lock error: \(err)")
121+
}
122+
123+
func unlock() {
124+
let err = pthread_mutex_unlock(_lock)
125+
precondition(err == 0, "pthread_mutex_unlock error: \(err)")
126+
}
127+
128+
func tryLock() -> Bool {
129+
pthread_mutex_trylock(_lock) == 0
130+
}
131+
132+
deinit {
133+
let err = pthread_mutex_destroy(self._lock)
134+
precondition(err == 0, "pthread_mutex_destroy error: \(err)")
135+
self._lock.deallocate()
136+
}
137+
}
138+
#elseif canImport(WinSDK)
139+
140+
import ucrt
141+
import WinSDK
142+
143+
final class Storage<ValueF> {
144+
private let _lock: UnsafeMutablePointer<SRWLOCK>
145+
146+
var value: ValueF
147+
148+
init(_ initialValue: ValueF) {
149+
self._lock = .allocate(capacity: 1)
150+
InitializeSRWLock(self._lock)
151+
self.value = initialValue
152+
}
153+
154+
func lock() {
155+
AcquireSRWLockExclusive(_lock)
156+
}
157+
158+
func unlock() {
159+
ReleaseSRWLockExclusive(_lock)
160+
}
161+
162+
func tryLock() -> Bool {
163+
TryAcquireSRWLockExclusive(_lock) != 0
164+
}
165+
}
166+
167+
#endif
168+
169+
#endif

0 commit comments

Comments
 (0)