11//
2- // AllocatedLock .swift
3- // AllocatedLock
2+ // Mutex .swift
3+ // swift-mutex
44//
55// Created by Simon Whitty on 10/04/2023.
66// Copyright 2023 Simon Whitty
77//
88// Distributed under the permissive MIT license
99// Get the latest version from here:
1010//
11- // https://github.com/swhitty/AllocatedLock
11+ // https://github.com/swhitty/swift-mutex
1212//
1313// Permission is hereby granted, free of charge, to any person obtaining a copy
1414// of this software and associated documentation files (the "Software"), to deal
2929// SOFTWARE.
3030//
3131
32- // Backports the Swift interface around os_unfair_lock_t available in recent Darwin platforms
33- //
32+ // Backports the Swift 6.0 Mutex API
3433@usableFromInline
35- struct AllocatedLock < State> : @unchecked Sendable {
36-
37- @usableFromInline
34+ package struct Mutex < Value> : @unchecked Sendable {
3835 let storage : Storage
36+ }
37+
38+ #if compiler(>=6)
39+ package extension Mutex {
3940
4041 @usableFromInline
41- init ( initialState : State ) {
42- self . storage = Storage ( initialState : initialState )
42+ init ( _ initialValue : consuming sending Value ) {
43+ self . storage = Storage ( initialValue )
4344 }
4445
45- @inlinable
46- func withLock< R> ( _ body: @Sendable ( inout State ) throws -> R ) rethrows -> R where R: Sendable {
46+ @usableFromInline
47+ borrowing func withLock< Result, E: Error > (
48+ _ body: ( inout sending Value) throws ( E ) -> sending Result
49+ ) throws ( E) -> sending Result {
4750 storage. lock ( )
4851 defer { storage. unlock ( ) }
49- return try body ( & storage. state )
52+ return try body ( & storage. value )
5053 }
51- }
52-
53- extension AllocatedLock where State == Void {
5454
55- init ( ) {
56- self . storage = Storage ( initialState: ( ) )
55+ @usableFromInline
56+ borrowing func withLockIfAvailable< Result, E> (
57+ _ body: ( inout sending Value) throws ( E ) -> sending Result
58+ ) throws ( E) -> sending Result? where E: Error {
59+ guard storage. tryLock ( ) else { return nil }
60+ defer { storage. unlock ( ) }
61+ return try body ( & storage. value)
5762 }
63+ }
64+ #else
65+ package extension Mutex {
5866
59- @inlinable @ available ( * , noasync )
60- func lock ( ) {
61- storage . lock ( )
67+ @usableFromInline
68+ init ( _ initialValue : Value ) {
69+ self . storage = Storage ( initialValue )
6270 }
6371
64- @inlinable @available ( * , noasync)
65- func unlock( ) {
66- storage. unlock ( )
72+ @usableFromInline
73+ borrowing func withLock< Result> (
74+ _ body: ( inout Value ) throws -> Result
75+ ) rethrows -> Result {
76+ storage. lock ( )
77+ defer { storage. unlock ( ) }
78+ return try body ( & storage. value)
6779 }
6880
69- @inlinable
70- func withLock< R> ( _ body: @Sendable ( ) throws -> R ) rethrows -> R where R: Sendable {
71- storage. lock ( )
81+ @usableFromInline
82+ borrowing func withLockIfAvailable< Result> (
83+ _ body: ( inout Value ) throws -> Result
84+ ) rethrows -> Result ? {
85+ guard storage. tryLock ( ) else { return nil }
7286 defer { storage. unlock ( ) }
73- return try body ( )
87+ return try body ( & storage . value )
7488 }
7589}
90+ #endif
7691
7792#if canImport(Darwin)
7893
7994import struct os. os_unfair_lock_t
8095import struct os. os_unfair_lock
8196import func os. os_unfair_lock_lock
8297import func os. os_unfair_lock_unlock
98+ import func os. os_unfair_lock_trylock
99+
100+ extension Mutex {
83101
84- extension AllocatedLock {
85- @usableFromInline
86102 final class Storage {
87103 private let _lock : os_unfair_lock_t
88104
89- @usableFromInline
90- var state : State
105+ var value : Value
91106
92- init ( initialState : State ) {
107+ init ( _ initialValue : Value ) {
93108 self . _lock = . allocate( capacity: 1 )
94109 self . _lock. initialize ( to: os_unfair_lock ( ) )
95- self . state = initialState
110+ self . value = initialValue
96111 }
97112
98- @usableFromInline
99113 func lock( ) {
100114 os_unfair_lock_lock ( _lock)
101115 }
102116
103- @usableFromInline
104117 func unlock( ) {
105118 os_unfair_lock_unlock ( _lock)
106119 }
107120
121+ func tryLock( ) -> Bool {
122+ os_unfair_lock_trylock ( _lock)
123+ }
124+
108125 deinit {
109126 self . _lock. deinitialize ( count: 1 )
110127 self . _lock. deallocate ( )
@@ -116,35 +133,36 @@ extension AllocatedLock {
116133
117134import Glibc
118135
119- extension AllocatedLock {
120- @ usableFromInline
136+ extension Mutex {
137+
121138 final class Storage {
122139 private let _lock : UnsafeMutablePointer < pthread_mutex_t >
123140
124- @usableFromInline
125- var state : State
141+ var value : Value
126142
127- init ( initialState : State ) {
143+ init ( _ initialValue : Value ) {
128144 var attr = pthread_mutexattr_t ( )
129145 pthread_mutexattr_init ( & attr)
130146 self . _lock = . allocate( capacity: 1 )
131147 let err = pthread_mutex_init ( self . _lock, & attr)
132148 precondition ( err == 0 , " pthread_mutex_init error: \( err) " )
133- self . state = initialState
149+ self . value = initialValue
134150 }
135151
136- @usableFromInline
137152 func lock( ) {
138153 let err = pthread_mutex_lock ( _lock)
139154 precondition ( err == 0 , " pthread_mutex_lock error: \( err) " )
140155 }
141156
142- @usableFromInline
143157 func unlock( ) {
144158 let err = pthread_mutex_unlock ( _lock)
145159 precondition ( err == 0 , " pthread_mutex_unlock error: \( err) " )
146160 }
147161
162+ func tryLock( ) -> Bool {
163+ pthread_mutex_trylock ( _lock) == 0
164+ }
165+
148166 deinit {
149167 let err = pthread_mutex_destroy ( self . _lock)
150168 precondition ( err == 0 , " pthread_mutex_destroy error: \( err) " )
@@ -158,29 +176,30 @@ extension AllocatedLock {
158176import ucrt
159177import WinSDK
160178
161- extension AllocatedLock {
162- @ usableFromInline
179+ extension Mutex {
180+
163181 final class Storage {
164182 private let _lock : UnsafeMutablePointer < SRWLOCK >
165183
166- @usableFromInline
167- var state : State
184+ var value : Value
168185
169- init ( initialState : State ) {
186+ init ( _ initialValue : Value ) {
170187 self . _lock = . allocate( capacity: 1 )
171188 InitializeSRWLock ( self . _lock)
172- self . state = initialState
189+ self . value = initialValue
173190 }
174191
175- @usableFromInline
176192 func lock( ) {
177193 AcquireSRWLockExclusive ( _lock)
178194 }
179195
180- @usableFromInline
181196 func unlock( ) {
182197 ReleaseSRWLockExclusive ( _lock)
183198 }
199+
200+ func tryLock( ) -> Bool {
201+ TryAcquireSRWLockExclusive ( _lock)
202+ }
184203 }
185204}
186205
0 commit comments