Skip to content

Commit b41ff07

Browse files
author
robot-vgsl
committed
Release 6.22.1
commit_hash:5f79bf67ca03abd426afa2c671efc0e83f55f984
1 parent 8a082b5 commit b41ff07

File tree

10 files changed

+119
-13
lines changed

10 files changed

+119
-13
lines changed

VGSLFundamentals/OSInfo.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,15 @@ public struct OSInfo: Sendable {
5050
}
5151

5252
#if INTERNAL_BUILD
53-
public static var current: Self = ._current
53+
private static let __current: AllocatedUnfairLock<Self> = .init(initialState: ._current)
54+
public static var current: Self {
55+
get {
56+
__current.withLock { $0 }
57+
}
58+
set {
59+
__current.withLock { $0 = newValue }
60+
}
61+
}
5462

5563
static func restoreSystemCurrent() {
5664
current = _current

VGSLFundamentals/concurrency/GCD.swift

+47
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,40 @@ public typealias DelayedExecution = (TimeInterval, @escaping () -> Void) -> Void
1010
public typealias DelayedRunner = (_ delay: TimeInterval, _ block: @escaping () -> Void)
1111
-> Cancellable
1212

13+
@_unavailableFromAsync(message: "await the call to the @MainActor closure directly")
14+
@available(iOS, introduced: 9.0, deprecated: 13.0, message: "Use MainActor.assumeIsolated instead.")
15+
private func backportedAssumeIsolatedToMainActor<T>(
16+
_ operation: @MainActor () throws -> T,
17+
file _: StaticString = #fileID, line _: UInt = #line
18+
) rethrows -> T where T: Sendable {
19+
typealias YesActor = @MainActor () throws -> T
20+
typealias NoActor = () throws -> T
21+
22+
assert(Thread.isMainThread)
23+
// To do the unsafe cast, we have to pretend it's @escaping.
24+
return try withoutActuallyEscaping(operation) {
25+
(_ fn: @escaping YesActor) throws -> T in
26+
let rawFn = unsafeBitCast(fn, to: NoActor.self)
27+
return try rawFn()
28+
}
29+
}
30+
31+
@_unavailableFromAsync(message: "await the call to the @MainActor closure directly")
32+
public func assumeIsolatedToMainActor<T>(
33+
_ operation: @MainActor () throws -> T,
34+
file _: StaticString = #fileID, line _: UInt = #line
35+
) rethrows -> T where T: Sendable {
36+
if #available(iOS 13.0, tvOS 13.0, *) {
37+
try MainActor.assumeIsolated {
38+
try operation()
39+
}
40+
} else {
41+
try backportedAssumeIsolatedToMainActor {
42+
try operation()
43+
}
44+
}
45+
}
46+
1347
public func onMainThread(_ block: @escaping () -> Void) {
1448
if Thread.isMainThread {
1549
block()
@@ -38,6 +72,19 @@ public func onMainThreadResult<T>(_ function: @escaping () -> Future<T>) -> Futu
3872
return future
3973
}
4074

75+
/// Executes a @MainActor closure by bypassing actor isolation checks.
76+
///
77+
/// - Warning: Only use if you fully understand the memory safety implications.
78+
@_unavailableFromAsync
79+
@inlinable
80+
@inline(__always)
81+
@_spi(Unsafe)
82+
public func runUnsafelyOnMainActor<T>(_ body: @MainActor () throws -> T) rethrows -> T {
83+
try withoutActuallyEscaping(body) { fn in
84+
try unsafeBitCast(fn, to: (() throws -> T).self)()
85+
}
86+
}
87+
4188
public func onMainThreadAsync(_ block: @escaping () -> Void) {
4289
DispatchQueue.main.async(execute: block)
4390
}

VGSLFundamentals/concurrency/RWLock.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22

33
import Foundation
44

5-
public var _RWLockUsesAllocatedUnfairLock = false
5+
private let __RWLockUsesAllocatedUnfairLock: AllocatedUnfairLock<Bool> = .init(initialState: false)
6+
public var _RWLockUsesAllocatedUnfairLock: Bool {
7+
get {
8+
__RWLockUsesAllocatedUnfairLock.withLock { $0 }
9+
}
10+
set {
11+
__RWLockUsesAllocatedUnfairLock.withLock { $0 = newValue }
12+
}
13+
}
614

715
public struct RWLock {
816
private let impl: any _ReadWriteLock

VGSLFundamentals/os/FileManaging.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Foundation
44

55
// swiftlint:disable use_make_instead_of_create
66

7-
public protocol FileManaging {
7+
public protocol FileManaging: Sendable {
88
var applicationSupportDirectory: URL { get }
99
var documentDirectory: URL { get }
1010
var libraryDirectory: URL { get }
@@ -18,7 +18,7 @@ public protocol FileManaging {
1818
func moveItem(at srcURL: URL, to dstURL: URL) throws
1919
}
2020

21-
extension FileManager: FileManaging {
21+
extension FileManager: @unchecked @retroactive Sendable, FileManaging {
2222
public var applicationSupportDirectory: URL {
2323
getSystemDirectoryURL(.applicationSupportDirectory)
2424
}

VGSLFundamentals/reactive/Lazy.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -297,5 +297,13 @@ extension Lazy {
297297
}
298298

299299
#if DEBUG
300-
public var _LazyTraceLoggingEnabled = false
300+
private let __LazyTraceLoggingEnabled: AllocatedUnfairLock<Bool> = .init(initialState: false)
301+
public var _LazyTraceLoggingEnabled: Bool {
302+
get {
303+
__LazyTraceLoggingEnabled.withLock { $0 }
304+
}
305+
set {
306+
__LazyTraceLoggingEnabled.withLock { $0 = newValue }
307+
}
308+
}
301309
#endif

VGSLFundamentals/reactive/Signal.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,13 @@ extension Signal {
223223
@inlinable
224224
public func delay(_ interval: TimeInterval) -> Signal {
225225
Signal { observer in
226-
var cancellable: Cancellable?
226+
let cancellable: AllocatedUnfairLock<Cancellable?> = .init(initialState: nil)
227227
let disposable = addObserver { t in
228-
cancellable = after(interval, onQueue: .main) { observer.action(t) }
228+
cancellable.withLock { $0 = after(interval, onQueue: .main) { observer.action(t) } }
229229
}
230230
return Disposable {
231231
disposable.dispose()
232-
cancellable?.cancel()
232+
cancellable.withLock { $0 }?.cancel()
233233
}
234234
}
235235
}

VGSLNetworking/Retrying/NetworkRetryIntervalSource.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ public final class HTTPHeaderRetryIntervalSource: NetworkRetryIntervalSource {
5757

5858
public final class LocalRetryIntervalSource: NetworkRetryIntervalSource {
5959
// Starting value of 1 sec should be a reasonable compromise for retries.
60-
private var retryingTimeout = RetryingTimeout(value: 1)
60+
private let retryingTimeout = AllocatedUnfairLock<RetryingTimeout>(initialState: .init(value: 1))
6161

6262
public init() {}
6363

6464
public func determineInterval(from error: NSError, since _: Date) -> TimeInterval? {
6565
if error.isNonRecoverableServerError { return nil }
66-
return retryingTimeout.getValueAndIncrement()
66+
return retryingTimeout.withLock { $0.getValueAndIncrement() }
6767
}
6868
}
6969

VGSLUI/PublicInterfaces.swift

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@
22

33
import CoreGraphics
44

5-
public var fontSpecifiers = FontSpecifiers(
5+
import VGSLFundamentals
6+
7+
private let _fontSpecifiers = AllocatedUnfairLock<FontSpecifiers>(initialState: .init(
68
text: systemFontSpecifier,
79
display: systemFontSpecifier
8-
)
10+
))
11+
public var fontSpecifiers: FontSpecifiers {
12+
get {
13+
_fontSpecifiers.withLock { $0 }
14+
}
15+
set {
16+
_fontSpecifiers.withLock { $0 = newValue }
17+
}
18+
}
919

1020
private let systemFontSpecifier = SystemFontSpecifier()
1121

VGSLUI/alert/AlertTextField.swift

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,38 @@
33
import Foundation
44

55
public struct AlertTextField: Equatable, Sendable {
6+
public enum ReturnKeyType: Sendable {
7+
case `default`
8+
case go
9+
case google
10+
case join
11+
case next
12+
case route
13+
case search
14+
case send
15+
case yahoo
16+
case done
17+
case emergencyCall
18+
case `continue`
19+
}
20+
621
public let placeholder: String?
722
public let initialText: String?
823
public let isSecureTextEntry: Bool
24+
public let enablesReturnKeyAutomatically: Bool
25+
public let returnKeyType: ReturnKeyType
926

1027
public init(
1128
placeholder: String? = nil,
1229
initialText: String? = nil,
13-
isSecureTextEntry: Bool = false
30+
isSecureTextEntry: Bool = false,
31+
enablesReturnKeyAutomatically: Bool = false,
32+
returnKeyType: ReturnKeyType = .default
1433
) {
1534
self.placeholder = placeholder
1635
self.initialText = initialText
1736
self.isSecureTextEntry = isSecureTextEntry
37+
self.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically
38+
self.returnKeyType = returnKeyType
1839
}
1940
}

VGSLUI/extensions/UIDeviceExtensions.swift

+4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ extension UIDevice {
1616
uname(&systemInfo)
1717
let identifier = withUnsafePointer(to: &systemInfo.machine) {
1818
$0.withMemoryRebound(to: CChar.self, capacity: 1) { ptr in
19+
#if swift(>=6.0)
1920
String(validatingCString: ptr)
21+
#else
22+
String(validatingUTF8: ptr)
23+
#endif
2024
}
2125
}
2226
#else

0 commit comments

Comments
 (0)