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.
import PackageDescription
@@ -13,5 +13,6 @@ let package = Package(
targets: [
.target(name: "Mustache", dependencies: []),
.testTarget(name: "MustacheTests", dependencies: ["Mustache"]),
]
],
swiftLanguageVersions: [.v5, .version("6")]
)

View File

@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
import Foundation
/// Protocol for content types
public protocol MustacheContentType: Sendable {
/// escape text for this content type eg for HTML replace "<" with "&lt;"
@@ -38,20 +40,33 @@ struct HTMLContentType: MustacheContentType {
/// the content type required. The default available types are `TEXT` and `HTML`. You can register your own
/// with `MustacheContentTypes.register`.
public enum MustacheContentTypes {
private static let lock = NSLock()
static func get(_ name: String) -> MustacheContentType? {
lock.withLock {
self.types[name]
}
}
/// Register new content type
/// - Parameters:
/// - contentType: Content type
/// - name: String to identify it
public static func register(_ contentType: MustacheContentType, named name: String) {
lock.withLock {
self.types[name] = contentType
}
}
static var types: [String: MustacheContentType] = [
private static let _types: [String: MustacheContentType] = [
"HTML": HTMLContentType(),
"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 {
/// 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
if !directory.hasSuffix("/") {
directory += "/"

View File

@@ -39,7 +39,7 @@ public struct MustacheLibrary: Sendable {
/// - Parameter directory: Directory to look for mustache templates
/// - Parameter extension: Extension of files to look for
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

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
public struct MustacheParserContext {
public struct MustacheParserContext: Sendable {
public let line: String
public let lineNumber: Int
public let columnNumber: Int

View File

@@ -65,11 +65,7 @@ extension MustacheTemplate {
}
}
#if hasFeature(RetroactiveAttribute)
extension MustacheTemplate: @retroactive Equatable {}
#else
extension MustacheTemplate: Equatable {}
#endif
extension MustacheTemplate.Token {
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 {}
#endif