Skip to content

Commit 2de3089

Browse files
authored
Add sendable conformance (#219)
* Bump swift tools version * Enable complete concurrency checking * Add sendable conformance
1 parent 224af35 commit 2de3089

14 files changed

Lines changed: 43 additions & 23 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
test-pushpull:
1111
runs-on: ubuntu-latest
12-
container: swift:5.9.2-jammy
12+
container: swift:5.10.1-jammy
1313
steps:
1414
- uses: actions/checkout@v3
1515
- name: Run tests

Package.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.9
1+
// swift-tools-version:5.10
22

33
import PackageDescription
44

@@ -25,16 +25,21 @@ let package = Package(
2525
.package(url: "https://github.com/apple/swift-collections.git", from: "1.1.4"),
2626
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.4.3"),
2727
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.3"),
28-
.package(url: "https://github.com/vapor/vapor.git", from: "4.114.1")
28+
.package(url: "https://github.com/vapor/vapor.git", from: "4.114.1"),
29+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.86.2")
2930
],
3031
targets: [
3132
.target(
3233
name: "HTMLKit",
3334
dependencies: [
3435
.product(name: "Collections", package: "swift-collections"),
3536
.product(name: "Logging", package: "swift-log"),
37+
.product(name: "NIO", package: "swift-nio")
3638
],
37-
exclude: ["Abstraction/README.md", "Framework/README.md"]
39+
exclude: ["Abstraction/README.md", "Framework/README.md"],
40+
swiftSettings: [
41+
.enableExperimentalFeature("StrictConcurrency=complete")
42+
]
3843
),
3944
.target(
4045
name: "HTMLKitConverter",
@@ -56,6 +61,10 @@ let package = Package(
5661
dependencies: [
5762
.target(name: "HTMLKit"),
5863
.product(name: "Vapor", package: "vapor"),
64+
.product(name: "NIO", package: "swift-nio")
65+
],
66+
swiftSettings: [
67+
.enableExperimentalFeature("StrictConcurrency=complete")
5968
]
6069
),
6170
.target(

Sources/HTMLKit/Framework/Environment/Environment.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import Foundation
2+
import NIOConcurrencyHelpers
23

34
/// A class that represents the environment
45
///
56
/// The environment provides storage for various settings used by the renderer
67
@_documentation(visibility: internal)
7-
public final class Environment {
8+
public final class Environment: @unchecked Sendable {
89

910
/// An enumeration of possible rendering errors.
1011
public enum Errors: Error {
@@ -43,10 +44,14 @@ public final class Environment {
4344
/// The storage of the environment
4445
private var storage: [AnyKeyPath: Any]
4546

47+
/// A lock to get sure, we are thread safe here
48+
private var lock: NIOLock
49+
4650
/// Initializes the environment
4751
public init() {
4852

4953
self.storage = [:]
54+
self.lock = .init()
5055
}
5156

5257
/// The current time zone of the environment
@@ -87,7 +92,10 @@ public final class Environment {
8792
///
8893
/// - Returns: The value
8994
public func retrieve(for path: AnyKeyPath) -> Any? {
90-
return storage[path]
95+
96+
return lock.withLock {
97+
return storage[path]
98+
}
9199
}
92100

93101
/// Inserts or updates a value in the environment for the given key path
@@ -96,7 +104,10 @@ public final class Environment {
96104
/// - value: The value to be stored or updated
97105
/// - path: The key path that identifies where the value is stored
98106
public func upsert<T>(_ value: T, for path: AnyKeyPath) {
99-
storage[path] = value
107+
108+
lock.withLock {
109+
storage[path] = value
110+
}
100111
}
101112

102113
/// Resolves an environment value

Sources/HTMLKit/Framework/Localization/Locale.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
///
33
/// A locale holds information about language, region and cultural preferences.
44
@_documentation(visibility: internal)
5-
public struct Locale: Hashable {
5+
public struct Locale: Hashable, Sendable {
66

77
/// A enumeration of potential language tags
8-
public enum Tag: String {
8+
public enum Tag: String, Sendable {
99

1010
case arabic = "ar"
1111
case belarusian = "be"

Sources/HTMLKit/Framework/Localization/Localization.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Foundation
22

33
/// A type that represents the localization
44
@_documentation(visibility: internal)
5-
public class Localization {
5+
public struct Localization: Sendable {
66

77
/// A enumeration of errors regarding the localization rendering
88
public enum Errors: Error, Equatable {
@@ -81,14 +81,14 @@ public class Localization {
8181
/// Sets the source directory
8282
///
8383
/// - Parameter source: The directory where the translations should be loaded from.
84-
public func set(source: URL) {
84+
public mutating func set(source: URL) {
8585
self.tables = load(source: source)
8686
}
8787

8888
/// Sets the default locale
8989
///
9090
/// - Parameter locale: A locale tag e.g. en-US
91-
public func set(locale: String) {
91+
public mutating func set(locale: String) {
9292
self.locale = Locale(tag: locale)
9393
}
9494

Sources/HTMLKit/Framework/Localization/TranslationTable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// A type that represents a translation table
22
///
33
/// A translation table stores multiple localized strings, mapping unique string keys to their corresponding translations
4-
internal struct TranslationTable {
4+
internal struct TranslationTable: Sendable {
55

66
/// The name of the table
77
internal let name: String

Sources/HTMLKit/Framework/Rendering/Encoding/Encoder.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import Foundation
77
/// > Note: The encoder does not utilize unicode encoding for some languages, such as JS and CSS.
88
/// > It primarily aims to preserve the code integrity and to protect against code injection within an
99
/// > HTML context.
10-
internal struct Encoder {
10+
internal struct Encoder: Sendable {
1111

1212
/// An enumeration of potential encoding mechanism
13-
internal enum Mechanism {
13+
internal enum Mechanism: Sendable {
1414

1515
/// The context the mechanism should be based on
16-
internal enum Context {
16+
internal enum Context: Sendable {
1717

1818
/// Mechanism to use on an attribute value
1919
case attribute

Sources/HTMLKit/Framework/Rendering/Encoding/Sanitizer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// A type responsible for sanitizing the renderer output
2-
internal struct Sanitizer {
2+
internal struct Sanitizer: Sendable {
33

44
/// Strip a tag from a given string
55
///

Sources/HTMLKit/Framework/Rendering/Features.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// An option set of different features
22
///
33
/// The feature set provides the flexibility to enable experimental features if desired.
4-
public struct Features: Swift.OptionSet {
4+
public struct Features: Swift.OptionSet, Sendable {
55

66
public var rawValue: Int
77

Sources/HTMLKit/Framework/Rendering/Markdown/Markdown.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
internal final class Markdown {
3+
internal struct Markdown: Sendable {
44

55
/// The markdowns characters
66
internal static let characters = CharacterSet(charactersIn: "*_~[`")

0 commit comments

Comments
 (0)