Support Swift 6 mode (#65)

* Enable swift 6 mode

* Attach Sendable

* Stop async context because enumerator can use only synchronous contexts

* Fix global shared mutable state for MustacheContentTypes

* Revert "Fix global shared mutable state for MustacheContentTypes"

This reverts commit d4ccc83e07aeb48f4aa4024b71eb8e5f70131bc5.

* Use  instead of lock

* Support 5 and 6 versions

* Lock on access in Swift 6

* Support 5.9

* Revert "Support 5.9"

This reverts commit 9845b3bc448b2af7238c3ac88aabe6d764b2e667.

* Fix 5.9 compatibility

* Unify to manage the same lock logic in 5.9 and 6

* Add withLock backport in NSLock
This commit is contained in:
Go Takagi
2025-03-26 18:53:44 +09:00
committed by GitHub
parent eeb4eec97f
commit 2add8847a1
7 changed files with 51 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
// swift-tools-version:5.7 // swift-tools-version:5.9
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@@ -13,5 +13,6 @@ let package = Package(
targets: [ targets: [
.target(name: "Mustache", dependencies: []), .target(name: "Mustache", dependencies: []),
.testTarget(name: "MustacheTests", dependencies: ["Mustache"]), .testTarget(name: "MustacheTests", dependencies: ["Mustache"]),
] ],
swiftLanguageVersions: [.v5, .version("6")]
) )

View File

@@ -12,6 +12,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
import Foundation
/// Protocol for content types /// Protocol for content types
public protocol MustacheContentType: Sendable { public protocol MustacheContentType: Sendable {
/// escape text for this content type eg for HTML replace "<" with "&lt;" /// escape text for this content type eg for HTML replace "<" with "&lt;"
@@ -38,8 +40,13 @@ struct HTMLContentType: MustacheContentType {
/// the content type required. The default available types are `TEXT` and `HTML`. You can register your own /// the content type required. The default available types are `TEXT` and `HTML`. You can register your own
/// with `MustacheContentTypes.register`. /// with `MustacheContentTypes.register`.
public enum MustacheContentTypes { public enum MustacheContentTypes {
private static let lock = NSLock()
static func get(_ name: String) -> MustacheContentType? { static func get(_ name: String) -> MustacheContentType? {
self.types[name] lock.withLock {
self.types[name]
}
} }
/// Register new content type /// Register new content type
@@ -47,11 +54,19 @@ public enum MustacheContentTypes {
/// - contentType: Content type /// - contentType: Content type
/// - name: String to identify it /// - name: String to identify it
public static func register(_ contentType: MustacheContentType, named name: String) { public static func register(_ contentType: MustacheContentType, named name: String) {
self.types[name] = contentType lock.withLock {
self.types[name] = contentType
}
} }
static var types: [String: MustacheContentType] = [ private static let _types: [String: MustacheContentType] = [
"HTML": HTMLContentType(), "HTML": HTMLContentType(),
"TEXT": TextContentType(), "TEXT": TextContentType(),
] ]
#if compiler(>=6.0)
nonisolated(unsafe) static var types: [String: MustacheContentType] = _types
#else
static var types: [String: MustacheContentType] = _types
#endif
} }

View File

@@ -16,7 +16,7 @@ import Foundation
extension MustacheLibrary { extension MustacheLibrary {
/// Load templates from a folder /// Load templates from a folder
static func loadTemplates(from directory: String, withExtension extension: String = "mustache") async throws -> [String: MustacheTemplate] { static func loadTemplates(from directory: String, withExtension extension: String = "mustache") throws -> [String: MustacheTemplate] {
var directory = directory var directory = directory
if !directory.hasSuffix("/") { if !directory.hasSuffix("/") {
directory += "/" directory += "/"

View File

@@ -39,7 +39,7 @@ public struct MustacheLibrary: Sendable {
/// - Parameter directory: Directory to look for mustache templates /// - Parameter directory: Directory to look for mustache templates
/// - Parameter extension: Extension of files to look for /// - Parameter extension: Extension of files to look for
public init(directory: String, withExtension extension: String = "mustache") async throws { public init(directory: String, withExtension extension: String = "mustache") async throws {
self.templates = try await Self.loadTemplates(from: directory, withExtension: `extension`) self.templates = try Self.loadTemplates(from: directory, withExtension: `extension`)
} }
/// Register template under name /// Register template under name

View File

@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Hummingbird server framework project
//
// Copyright (c) 2021-2021 the Hummingbird authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if compiler(<6.0)
import Foundation
extension NSLock {
func withLock<Value>(_ operation: () throws -> Value) rethrows -> Value {
self.lock()
defer {
self.unlock()
}
return try operation()
}
}
#endif

View File

@@ -303,7 +303,7 @@ extension Parser {
} }
/// context used in parser error /// context used in parser error
public struct MustacheParserContext { public struct MustacheParserContext: Sendable {
public let line: String public let line: String
public let lineNumber: Int public let lineNumber: Int
public let columnNumber: Int public let columnNumber: Int

View File

@@ -65,11 +65,7 @@ extension MustacheTemplate {
} }
} }
#if hasFeature(RetroactiveAttribute)
extension MustacheTemplate: @retroactive Equatable {}
#else
extension MustacheTemplate: Equatable {} extension MustacheTemplate: Equatable {}
#endif
extension MustacheTemplate.Token { extension MustacheTemplate.Token {
public static func == (lhs: MustacheTemplate.Token, rhs: MustacheTemplate.Token) -> Bool { public static func == (lhs: MustacheTemplate.Token, rhs: MustacheTemplate.Token) -> Bool {
@@ -92,8 +88,4 @@ extension MustacheTemplate.Token {
} }
} }
#if hasFeature(RetroactiveAttribute)
extension MustacheTemplate.Token: @retroactive Equatable {}
#else
extension MustacheTemplate.Token: Equatable {} extension MustacheTemplate.Token: Equatable {}
#endif