Skip to content

Commit 0856c1d

Browse files
committed
[WIP] Dependency traits
1 parent bc74ac0 commit 0856c1d

File tree

4 files changed

+407
-9
lines changed

4 files changed

+407
-9
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// This source file is part of the Swift.org open source project
3+
//
4+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See https://swift.org/LICENSE.txt for license information
8+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
//
10+
11+
/// A type whose instances can run a series of work items in strict order.
12+
///
13+
/// When a work item is scheduled on an instance of this type, it runs after any
14+
/// previously-scheduled work items. If it suspends, subsequently-scheduled work
15+
/// items do not start running; they must wait until the suspended work item
16+
/// either returns or throws an error.
17+
final actor Serializer {
18+
/// The number of scheduled work items, including (possibly) the one currently
19+
/// running.
20+
private var scheduledCount = 0
21+
22+
/// Continuations for any scheduled work items that haven't started yet.
23+
private var continuations = [CheckedContinuation<Void, Never>]()
24+
25+
/// Run a work item serially after any previously-scheduled work items.
26+
///
27+
/// - Parameters:
28+
/// - workItem: A closure to run.
29+
///
30+
/// - Returns: Whatever is returned from `workItem`.
31+
///
32+
/// - Throws: Whatever is thrown by `workItem`.
33+
func run<R>(_ workItem: @Sendable @isolated(any) () async throws -> sending R) async rethrows -> R {
34+
scheduledCount += 1
35+
defer {
36+
// Resume the next scheduled closure.
37+
if !continuations.isEmpty {
38+
let continuation = continuations.removeFirst()
39+
continuation.resume()
40+
}
41+
42+
scheduledCount -= 1
43+
}
44+
45+
await withCheckedContinuation { continuation in
46+
if scheduledCount == 1 {
47+
// Nothing else was scheduled, so we can resume immediately.
48+
continuation.resume()
49+
} else {
50+
// Something was scheduled, so add the continuation to the list. When it
51+
// resumes, we can run.
52+
continuations.append(continuation)
53+
}
54+
}
55+
56+
return try await workItem()
57+
}
58+
}
59+

Sources/Testing/Support/Environment.swift

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,24 +89,41 @@ enum Environment {
8989
}()
9090
#endif
9191

92+
/// The address of the environment block, if available.
93+
///
94+
/// The value of this property is always `nil` on Windows and on platforms
95+
/// that do not support environment variables.
96+
static var unsafeAddress: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>? {
97+
#if SWT_NO_ENVIRONMENT_VARIABLES
98+
nil
99+
#elseif SWT_TARGET_OS_APPLE
100+
_NSGetEnviron()?.pointee
101+
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
102+
swt_environ()
103+
#elseif os(WASI)
104+
__wasilibc_get_environ()
105+
#elseif os(Windows)
106+
nil
107+
#else
108+
#warning("Platform-specific implementation missing: environment variables unavailable")
109+
nil
110+
#endif
111+
}
112+
92113
/// Get all environment variables in the current process.
93114
///
94115
/// - Returns: A copy of the current process' environment dictionary.
95116
static func get() -> [String: String] {
96117
#if SWT_NO_ENVIRONMENT_VARIABLES
97118
simulatedEnvironment.rawValue
98-
#elseif SWT_TARGET_OS_APPLE
99-
#if !SWT_NO_DYNAMIC_LINKING
119+
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
120+
#if SWT_TARGET_OS_APPLE && !SWT_NO_DYNAMIC_LINKING
100121
_environ_lock_np?()
101122
defer {
102123
_environ_unlock_np?()
103124
}
104125
#endif
105-
return _get(fromEnviron: _NSGetEnviron()!.pointee!)
106-
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
107-
_get(fromEnviron: swt_environ())
108-
#elseif os(WASI)
109-
_get(fromEnviron: __wasilibc_get_environ())
126+
return _get(fromEnviron: Self.unsafeAddress!)
110127
#elseif os(Windows)
111128
guard let environ = GetEnvironmentStringsW() else {
112129
return [:]
@@ -153,7 +170,9 @@ enum Environment {
153170
defer {
154171
_environ_unlock_np?()
155172
}
156-
let environ = _NSGetEnviron()!.pointee!
173+
guard let environ = Self.unsafeAddress else {
174+
return nil
175+
}
157176

158177
return name.withCString { name in
159178
for i in 0... {

0 commit comments

Comments
 (0)