-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support loading trust root CAs on Linux (#136)
* Support loading trust roots on Linux * Fix linux * run `swift-format` * Apply review feedback * Implement `_TinyArray2` * fix tests * Update benchmarks for _TinyArray2 * run swift-format * use two properties instead of TinyArray2 * remove usage of `_TinyArray2` and rename `insert` to `append` * remove TinyArray2 and rename TinyArray1 back to just TinyArray * run swift-format * fix tests * Fix review comments
- Loading branch information
Showing
15 changed files
with
4,001 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftCertificates open source project | ||
// | ||
// Copyright (c) 2023 Apple Inc. and the SwiftCertificates project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import Foundation | ||
|
||
final class LockedValueBox<Value> { | ||
private let _lock: NSLock = .init() | ||
private var _value: Value | ||
|
||
var unsafeUnlockedValue: Value { | ||
get { _value } | ||
set { _value = newValue } | ||
} | ||
|
||
func lock() { | ||
_lock.lock() | ||
} | ||
|
||
func unlock() { | ||
_lock.unlock() | ||
} | ||
|
||
init(_ value: Value) { | ||
self._value = value | ||
} | ||
|
||
func withLockedValue<Result>( | ||
_ body: (inout Value) throws -> Result | ||
) rethrows -> Result { | ||
try _lock.withLock { | ||
try body(&_value) | ||
} | ||
} | ||
} | ||
|
||
extension LockedValueBox: @unchecked Sendable where Value: Sendable {} | ||
|
||
extension NSLock { | ||
// this API doesn't exist on Linux and therefore we have a copy of it here | ||
func withLock<Result>(_ body: () throws -> Result) rethrows -> Result { | ||
self.lock() | ||
defer { self.unlock() } | ||
return try body() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftCertificates open source project | ||
// | ||
// Copyright (c) 2023 Apple Inc. and the SwiftCertificates project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// MARK: - Promise | ||
final class Promise<Value, Failure: Error> { | ||
private enum State { | ||
case unfulfilled(observers: [CheckedContinuation<Result<Value, Failure>, Never>]) | ||
case fulfilled(Result<Value, Failure>) | ||
} | ||
|
||
private let state = LockedValueBox(State.unfulfilled(observers: [])) | ||
|
||
init() {} | ||
|
||
fileprivate var result: Result<Value, Failure> { | ||
get async { | ||
self.state.lock() | ||
|
||
switch self.state.unsafeUnlockedValue { | ||
case .fulfilled(let result): | ||
defer { self.state.unlock() } | ||
return result | ||
|
||
case .unfulfilled(var observers): | ||
return await withCheckedContinuation { | ||
(continuation: CheckedContinuation<Result<Value, Failure>, Never>) in | ||
observers.append(continuation) | ||
self.state.unsafeUnlockedValue = .unfulfilled(observers: observers) | ||
self.state.unlock() | ||
} | ||
} | ||
} | ||
} | ||
|
||
func fulfil(with result: Result<Value, Failure>) { | ||
self.state.withLockedValue { state in | ||
switch state { | ||
case .fulfilled(let oldResult): | ||
fatalError("tried to fulfil Promise that is already fulfilled to \(oldResult). New result: \(result)") | ||
case .unfulfilled(let observers): | ||
for observer in observers { | ||
observer.resume(returning: result) | ||
} | ||
state = .fulfilled(result) | ||
} | ||
} | ||
} | ||
|
||
deinit { | ||
self.state.withLockedValue { | ||
switch $0 { | ||
case .fulfilled: | ||
break | ||
case .unfulfilled: | ||
fatalError("unfulfilled Promise leaked") | ||
} | ||
} | ||
} | ||
} | ||
|
||
extension Promise: Sendable where Value: Sendable {} | ||
|
||
extension Promise { | ||
func succeed(with value: Value) { | ||
self.fulfil(with: .success(value)) | ||
} | ||
|
||
func fail(with error: Failure) { | ||
self.fulfil(with: .failure(error)) | ||
} | ||
} | ||
|
||
// MARK: - Future | ||
|
||
struct Future<Value, Failure: Error> { | ||
private let promise: Promise<Value, Failure> | ||
|
||
init(_ promise: Promise<Value, Failure>) { | ||
self.promise = promise | ||
} | ||
|
||
var result: Result<Value, Failure> { | ||
get async { | ||
await promise.result | ||
} | ||
} | ||
} | ||
|
||
extension Future: Sendable where Value: Sendable {} | ||
|
||
extension Future { | ||
var value: Value { | ||
get async throws { | ||
try await result.get() | ||
} | ||
} | ||
} | ||
|
||
extension Future where Failure == Never { | ||
var value: Value { | ||
get async { | ||
await result.get() | ||
} | ||
} | ||
} | ||
|
||
extension Result where Failure == Never { | ||
func get() -> Success { | ||
switch self { | ||
case .success(let success): | ||
return success | ||
} | ||
} | ||
} |
Oops, something went wrong.