Skip to content

Commit 73efb1f

Browse files
committed
Start removing futures and port to Swift Testing
1 parent 73f4ad4 commit 73efb1f

24 files changed

+1652
-1745
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
DerivedData
66
Package.resolved
77
.swiftpm
8-
8+
.index-build

.swift-format

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"fileScopedDeclarationPrivacy": {
3+
"accessLevel": "private"
4+
},
5+
"indentation": {
6+
"spaces": 4
7+
},
8+
"indentConditionalCompilationBlocks": false,
9+
"indentSwitchCaseLabels": false,
10+
"lineBreakAroundMultilineExpressionChainComponents": false,
11+
"lineBreakBeforeControlFlowKeywords": false,
12+
"lineBreakBeforeEachArgument": false,
13+
"lineBreakBeforeEachGenericRequirement": false,
14+
"lineLength": 140,
15+
"maximumBlankLines": 1,
16+
"multiElementCollectionTrailingCommas": true,
17+
"noAssignmentInExpressions": {
18+
"allowedFunctions": [
19+
"XCTAssertNoThrow"
20+
]
21+
},
22+
"prioritizeKeepingFunctionOutputTogether": false,
23+
"respectsExistingLineBreaks": true,
24+
"rules": {
25+
"AllPublicDeclarationsHaveDocumentation": false,
26+
"AlwaysUseLiteralForEmptyCollectionInit": false,
27+
"AlwaysUseLowerCamelCase": true,
28+
"AmbiguousTrailingClosureOverload": true,
29+
"BeginDocumentationCommentWithOneLineSummary": false,
30+
"DoNotUseSemicolons": true,
31+
"DontRepeatTypeInStaticProperties": true,
32+
"FileScopedDeclarationPrivacy": true,
33+
"FullyIndirectEnum": true,
34+
"GroupNumericLiterals": true,
35+
"IdentifiersMustBeASCII": true,
36+
"NeverForceUnwrap": false,
37+
"NeverUseForceTry": false,
38+
"NeverUseImplicitlyUnwrappedOptionals": false,
39+
"NoAccessLevelOnExtensionDeclaration": true,
40+
"NoAssignmentInExpressions": true,
41+
"NoBlockComments": true,
42+
"NoCasesWithOnlyFallthrough": true,
43+
"NoEmptyTrailingClosureParentheses": true,
44+
"NoLabelsInCasePatterns": true,
45+
"NoLeadingUnderscores": false,
46+
"NoParensAroundConditions": true,
47+
"NoPlaygroundLiterals": true,
48+
"NoVoidReturnOnFunctionSignature": true,
49+
"OmitExplicitReturns": false,
50+
"OneCasePerLine": true,
51+
"OneVariableDeclarationPerLine": true,
52+
"OnlyOneTrailingClosureArgument": true,
53+
"OrderedImports": true,
54+
"ReplaceForEachWithForLoop": true,
55+
"ReturnVoidInsteadOfEmptyTuple": true,
56+
"TypeNamesShouldBeCapitalized": true,
57+
"UseEarlyExits": false,
58+
"UseExplicitNilCheckInConditions": true,
59+
"UseLetInEveryBoundCaseVariable": true,
60+
"UseShorthandTypeNames": true,
61+
"UseSingleLinePropertyGetter": true,
62+
"UseSynthesizedInitializer": true,
63+
"UseTripleSlashForDocumentationComments": true,
64+
"UseWhereClausesInForLoops": false,
65+
"ValidateDocumentationComments": false
66+
},
67+
"spacesAroundRangeFormationOperators": false,
68+
"tabWidth": 4,
69+
"version": 1
70+
}

Package.swift

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.10
1+
// swift-tools-version:6.0
22
import PackageDescription
33

44
let package = Package(
@@ -13,7 +13,7 @@ let package = Package(
1313
.library(name: "LeafKit", targets: ["LeafKit"])
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
16+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0")
1717
],
1818
targets: [
1919
.target(
@@ -28,20 +28,18 @@ let package = Package(
2828
.testTarget(
2929
name: "LeafKitTests",
3030
dependencies: [
31-
.target(name: "LeafKit"),
31+
.target(name: "LeafKit")
3232
],
3333
exclude: [
34-
"Templates",
34+
"Templates"
3535
],
3636
swiftSettings: swiftSettings
3737
),
3838
]
3939
)
4040

41-
var swiftSettings: [SwiftSetting] { [
42-
.enableUpcomingFeature("ExistentialAny"),
43-
.enableUpcomingFeature("ConciseMagicFile"),
44-
.enableUpcomingFeature("ForwardTrailingClosures"),
45-
.enableUpcomingFeature("DisableOutwardActorInference"),
46-
.enableExperimentalFeature("StrictConcurrency=complete"),
47-
] }
41+
var swiftSettings: [SwiftSetting] {
42+
[
43+
.enableUpcomingFeature("ExistentialAny")
44+
]
45+
}
Lines changed: 33 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,83 @@
1-
import NIOCore
21
import NIOConcurrencyHelpers
2+
import NIOCore
33

4-
public final class DefaultLeafCache: SynchronousLeafCache {
4+
public actor DefaultLeafCache: LeafCache {
55
// MARK: - Public - `LeafCache` Protocol Conformance
6-
6+
77
/// Global setting for enabling or disabling the cache
8-
public var isEnabled: Bool = true
8+
private(set) public var isEnabled: Bool = true
99
/// Current count of cached documents
10-
public var count: Int {
11-
self.lock.withLock { self.cache.count }
12-
}
10+
public var count: Int { self.cache.count }
1311

1412
/// Initializer
1513
public init() {
16-
self.lock = .init()
1714
self.cache = [:]
1815
}
1916

17+
public func toggleEnabled() {
18+
self.isEnabled = !isEnabled
19+
}
20+
2021
/// - Parameters:
2122
/// - document: The `LeafAST` to store
2223
/// - loop: `EventLoop` to return futures on
2324
/// - replace: If a document with the same name is already cached, whether to replace or not.
2425
/// - Returns: The document provided as an identity return
25-
public func insert(
26-
_ document: LeafAST,
27-
on loop: any EventLoop,
28-
replace: Bool = false
29-
) -> EventLoopFuture<LeafAST> {
26+
public func insert(_ document: LeafAST, replace: Bool = false) async throws -> LeafAST {
3027
// future fails if caching is enabled
3128
guard self.isEnabled else {
32-
return loop.makeSucceededFuture(document)
29+
return document
3330
}
3431

35-
return self.lock.withLock {
36-
// return an error if replace is false and the document name is already in cache
37-
switch (self.cache.keys.contains(document.name), replace) {
38-
case (true, false):
39-
return loop.makeFailedFuture(LeafError(.keyExists(document.name)))
40-
default:
41-
self.cache[document.name] = document
42-
}
43-
return loop.makeSucceededFuture(document)
32+
// return an error if replace is false and the document name is already in cache
33+
switch (self.cache.keys.contains(document.name), replace) {
34+
case (true, false):
35+
throw LeafError(.keyExists(document.name))
36+
default:
37+
self.cache[document.name] = document
4438
}
39+
return document
4540
}
46-
41+
4742
/// - Parameters:
4843
/// - documentName: Name of the `LeafAST` to try to return
4944
/// - loop: `EventLoop` to return futures on
5045
/// - Returns: `EventLoopFuture<LeafAST?>` holding the `LeafAST` or nil if no matching result
51-
public func retrieve(
52-
documentName: String,
53-
on loop: any EventLoop
54-
) -> EventLoopFuture<LeafAST?> {
46+
public func retrieve(documentName: String) async throws -> LeafAST? {
5547
guard self.isEnabled else {
56-
return loop.makeSucceededFuture(nil)
57-
}
58-
return self.lock.withLock {
59-
loop.makeSucceededFuture(self.cache[documentName])
48+
return nil
6049
}
50+
return self.cache[documentName]
6151
}
6252

6353
/// - Parameters:
6454
/// - documentName: Name of the `LeafAST` to try to purge from the cache
6555
/// - loop: `EventLoop` to return futures on
6656
/// - Returns: `EventLoopFuture<Bool?>` - If no document exists, returns nil. If removed,
6757
/// returns true. If cache can't remove because of dependencies (not yet possible), returns false.
68-
public func remove(
69-
_ documentName: String,
70-
on loop: any EventLoop
71-
) -> EventLoopFuture<Bool?> {
58+
public func remove(_ documentName: String) async throws -> Bool? {
7259
guard self.isEnabled else {
73-
return loop.makeFailedFuture(LeafError(.cachingDisabled))
60+
throw LeafError(.cachingDisabled)
7461
}
7562

76-
return self.lock.withLock {
77-
guard self.cache[documentName] != nil else {
78-
return loop.makeSucceededFuture(nil)
79-
}
80-
self.cache[documentName] = nil
81-
return loop.makeSucceededFuture(true)
63+
guard self.cache[documentName] != nil else {
64+
return nil
8265
}
66+
self.cache[documentName] = nil
67+
return true
8368
}
84-
69+
8570
// MARK: - Internal Only
86-
87-
let lock: NIOLock
8871
var cache: [String: LeafAST]
89-
72+
9073
/// Blocking file load behavior
9174
func retrieve(documentName: String) throws -> LeafAST? {
9275
guard self.isEnabled else {
9376
throw LeafError(.cachingDisabled)
9477
}
95-
return try self.lock.withLock {
96-
guard let result = self.cache[documentName] else {
97-
throw LeafError(.noValueForKey(documentName))
98-
}
99-
return result
78+
guard let result = self.cache[documentName] else {
79+
throw LeafError(.noValueForKey(documentName))
10080
}
81+
return result
10182
}
10283
}

Sources/LeafKit/LeafCache/LeafCache.swift

Lines changed: 12 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,67 +14,26 @@ import NIOCore
1414
/// `LeafAST.name` is to be used in all cases as the key for retrieving cached documents.
1515
public protocol LeafCache {
1616
/// Global setting for enabling or disabling the cache
17-
var isEnabled : Bool { get set }
17+
var isEnabled: Bool { get async }
1818
/// Current count of cached documents
19-
var count: Int { get }
20-
19+
var count: Int { get async }
20+
21+
func toggleEnabled() async
22+
2123
/// - Parameters:
2224
/// - document: The `LeafAST` to store
23-
/// - loop: `EventLoop` to return futures on
2425
/// - replace: If a document with the same name is already cached, whether to replace or not.
2526
/// - Returns: The document provided as an identity return (or a failed future if it can't be inserted)
26-
func insert(
27-
_ document: LeafAST,
28-
on loop: any EventLoop,
29-
replace: Bool
30-
) -> EventLoopFuture<LeafAST>
31-
27+
func insert(_ document: LeafAST, replace: Bool) async throws -> LeafAST
28+
3229
/// - Parameters:
33-
/// - documentName: Name of the `LeafAST` to try to return
34-
/// - loop: `EventLoop` to return futures on
35-
/// - Returns: `EventLoopFuture<LeafAST?>` holding the `LeafAST` or nil if no matching result
36-
func retrieve(
37-
documentName: String,
38-
on loop: any EventLoop
39-
) -> EventLoopFuture<LeafAST?>
30+
/// - documentName: Name of the `LeafAST` to try to return
31+
/// - Returns: `LeafAST?` holding the `LeafAST` or nil if no matching result
32+
func retrieve(documentName: String) async throws -> LeafAST?
4033

4134
/// - Parameters:
4235
/// - documentName: Name of the `LeafAST` to try to purge from the cache
43-
/// - loop: `EventLoop` to return futures on
44-
/// - Returns: `EventLoopFuture<Bool?>` - If no document exists, returns nil. If removed,
36+
/// - Returns: `Bool?` - If no document exists, returns nil. If removed,
4537
/// returns true. If cache can't remove because of dependencies (not yet possible), returns false.
46-
func remove(
47-
_ documentName: String,
48-
on loop: any EventLoop
49-
) -> EventLoopFuture<Bool?>
50-
}
51-
52-
/// A `LeafCache` that provides certain blocking methods for non-future access to the cache
53-
///
54-
/// Adherents *MUST* be thread-safe and *SHOULD NOT* be blocking simply to avoid futures -
55-
/// only adhere to this protocol if using futures is needless overhead
56-
protocol SynchronousLeafCache: LeafCache {
57-
/// - Parameters:
58-
/// - document: The `LeafAST` to store
59-
/// - replace: If a document with the same name is already cached, whether to replace or not
60-
/// - Returns: The document provided as an identity return, or nil if it can't guarantee completion rapidly
61-
/// - Throws: `LeafError` .keyExists if replace is false and document already exists
62-
func insert(_ document: LeafAST, replace: Bool) throws -> LeafAST?
63-
64-
/// - Parameter documentName: Name of the `LeafAST` to try to return
65-
/// - Returns: The requested `LeafAST` or nil if it can't guarantee completion rapidly
66-
/// - Throws: `LeafError` .noValueForKey if no such document is cached
67-
func retrieve(documentName: String) throws -> LeafAST?
68-
69-
/// - Parameter documentName: Name of the `LeafAST` to try to purge from the cache
70-
/// - Returns: `Bool?` If removed, returns true. If cache can't remove because of dependencies
71-
/// (not yet possible), returns false. Nil if it can't guarantee completion rapidly.
72-
/// - Throws: `LeafError` .noValueForKey if no such document is cached
73-
func remove(documentName: String) throws -> Bool?
74-
}
75-
76-
extension SynchronousLeafCache {
77-
func insert(_ document: LeafAST, replace: Bool) throws -> LeafAST? { nil }
78-
func retrieve(documentName: String) throws -> LeafAST? { nil }
79-
func remove(documentName: String) throws -> Bool? { nil }
38+
func remove(_ documentName: String) async throws -> Bool?
8039
}

0 commit comments

Comments
 (0)