diff --git a/bin/configs/swift6-validation.yaml b/bin/configs/swift6-validation.yaml
index d2ab2c83fb36..40ac79a70718 100644
--- a/bin/configs/swift6-validation.yaml
+++ b/bin/configs/swift6-validation.yaml
@@ -5,6 +5,7 @@ templateDir: modules/openapi-generator/src/main/resources/swift6
generateAliasAsModel: true
additionalProperties:
useSPMFileStructure: false
+ nonisolatedModels: true
podAuthors: ""
podSummary: PetstoreClient
projectName: PetstoreClient
diff --git a/docs/generators/swift6.md b/docs/generators/swift6.md
index 4be56233e01b..20058cdaf614 100644
--- a/docs/generators/swift6.md
+++ b/docs/generators/swift6.md
@@ -36,6 +36,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|library|Library template (sub-template) to use|
- **urlsession**
- [DEFAULT] HTTP client: URLSession
- **alamofire**
- HTTP client: Alamofire
- **vapor**
- HTTP client: Vapor
|urlsession|
|mapFileBinaryToData|Map File and Binary to Data (default: false)| |false|
|nonPublicApi|Generates code with reduced access modifiers; allows embedding elsewhere without exposing non-public API calls to consumers.(default: false)| |null|
+|nonisolatedModels|Mark generated models, and the supporting protocols, extensions and helper types they rely on, as nonisolated so they stay usable off the main actor in modules built with default MainActor isolation (SE-0466). Requires a Swift 6.1+ toolchain (default: false)| |false|
|objcCompatible|Add additional properties and methods for Objective-C compatibility (default: false)| |null|
|oneOfUnknownDefaultCase|Add unknownDefault case to oneOf enum (default: false)| |false|
|podAuthors|Authors used for Podspec| |null|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java
index 2abc8fb13c82..f2ddccb8ddfd 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java
@@ -79,6 +79,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
public static final String GENERATE_MODEL_ADDITIONAL_PROPERTIES = "generateModelAdditionalProperties";
public static final String HASHABLE_MODELS = "hashableModels";
public static final String IDENTIFIABLE_MODELS = "identifiableModels";
+ public static final String NONISOLATED_MODELS = "nonisolatedModels";
public static final String USE_PARAMETER_CONVERTIBLE = "useParameterConvertible";
public static final String MAP_FILE_BINARY_TO_DATA = "mapFileBinaryToData";
public static final String USE_CUSTOM_DATE_WITHOUT_TIME = "useCustomDateWithoutTime";
@@ -125,6 +126,8 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
@Setter
protected boolean identifiableModels = true;
@Setter
+ protected boolean nonisolatedModels = false;
+ @Setter
protected boolean useParameterConvertible = true;
@Getter
@Setter
@@ -379,6 +382,12 @@ public Swift6ClientCodegen() {
"Make models conform to Identifiable when an id is present (default: true)")
.defaultValue(Boolean.TRUE.toString()));
+ cliOptions.add(new CliOption(NONISOLATED_MODELS,
+ "Mark generated models, and the supporting protocols, extensions and helper types they rely on, "
+ + "as nonisolated so they stay usable off the main actor in modules built with default MainActor isolation (SE-0466). "
+ + "Requires a Swift 6.1+ toolchain (default: false)")
+ .defaultValue(Boolean.FALSE.toString()));
+
cliOptions.add(new CliOption(USE_PARAMETER_CONVERTIBLE,
"Make models conform to ParameterConvertible protocol (default: true)")
.defaultValue(Boolean.TRUE.toString()));
@@ -619,6 +628,11 @@ public void processOpts() {
}
additionalProperties.put(IDENTIFIABLE_MODELS, identifiableModels);
+ if (additionalProperties.containsKey(NONISOLATED_MODELS)) {
+ setNonisolatedModels(convertPropertyToBooleanAndWriteBack(NONISOLATED_MODELS));
+ }
+ additionalProperties.put(NONISOLATED_MODELS, nonisolatedModels);
+
if (additionalProperties.containsKey(USE_PARAMETER_CONVERTIBLE)) {
setUseParameterConvertible(convertPropertyToBooleanAndWriteBack(USE_PARAMETER_CONVERTIBLE));
}
diff --git a/modules/openapi-generator/src/main/resources/swift6/CodableHelper.mustache b/modules/openapi-generator/src/main/resources/swift6/CodableHelper.mustache
index f9bb64bb0b57..b0f4b2d20f4d 100644
--- a/modules/openapi-generator/src/main/resources/swift6/CodableHelper.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/CodableHelper.mustache
@@ -7,7 +7,7 @@
import Foundation
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class CodableHelper: @unchecked Sendable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}class CodableHelper: @unchecked Sendable {
// MARK: - Private state
diff --git a/modules/openapi-generator/src/main/resources/swift6/Extensions.mustache b/modules/openapi-generator/src/main/resources/swift6/Extensions.mustache
index 7145643cddc4..673a0981b67e 100644
--- a/modules/openapi-generator/src/main/resources/swift6/Extensions.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/Extensions.mustache
@@ -11,53 +11,53 @@ import FoundationNetworking
@preconcurrency import PromiseKit{{/usePromiseKit}}{{#useVapor}}
import Vapor{{/useVapor}}{{^useVapor}}
-extension Bool: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Bool: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Float: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Float: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Int: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int32: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Int32: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int64: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Int64: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Double: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Double: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Decimal: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Decimal: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension String: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension String: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension URL: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension URL: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension UUID: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension UUID: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension RawRepresentable where RawValue: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension RawRepresentable where RawValue: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
rawValue.asParameter(codableHelper: codableHelper)
}
}
-private func encodeIfPossible(_ object: T, codableHelper: CodableHelper) -> any Sendable {
+private {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}func encodeIfPossible(_ object: T, codableHelper: CodableHelper) -> any Sendable {
if let encodableObject = object as? ParameterConvertible {
return encodableObject.asParameter(codableHelper: codableHelper)
} else {
@@ -65,19 +65,19 @@ private func encodeIfPossible(_ object: T, codableHelper: CodableHe
}
}
-extension Array where Element: Sendable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Array where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.map { encodeIfPossible($0, codableHelper: codableHelper) }
}
}
-extension Set where Element: Sendable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Set where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return Array(self).asParameter(codableHelper: codableHelper)
}
}
-extension Dictionary where Key: Sendable, Value: Sendable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Dictionary where Key: Sendable, Value: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
var dictionary = [Key: any Sendable]()
for (key, value) in self {
@@ -87,19 +87,19 @@ extension Dictionary where Key: Sendable, Value: Sendable {
}
}
-extension Data: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Data: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.base64EncodedString(options: Data.Base64EncodingOptions())
}
}
-extension Date: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension Date: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return codableHelper.dateFormatter.string(from: self)
}
}{{/useVapor}}{{#generateModelAdditionalProperties}}
-extension String: @retroactive CodingKey {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension String: @retroactive CodingKey {
public var stringValue: String {
return self
@@ -119,7 +119,7 @@ extension String: @retroactive CodingKey {
}
-extension KeyedEncodingContainerProtocol {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension KeyedEncodingContainerProtocol {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} mutating func encodeArray(_ values: [T], forKey key: Self.Key) throws where T: Encodable {
var arrayContainer = nestedUnkeyedContainer(forKey: key)
@@ -161,7 +161,7 @@ extension KeyedEncodingContainerProtocol {
}
}
-extension KeyedDecodingContainerProtocol {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension KeyedDecodingContainerProtocol {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func decodeArray(_ type: T.Type, forKey key: Self.Key) throws -> [T] where T: Decodable {
var tmpArray = [T]()
@@ -281,4 +281,4 @@ extension Set: @retroactive AsyncRequestDecodable where Element: Content {
extension Set: @retroactive Content where Element: Content { }
-extension JSONValue: Content {}{{/useVapor}}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: Content {}{{/useVapor}}
diff --git a/modules/openapi-generator/src/main/resources/swift6/JSONValue.mustache b/modules/openapi-generator/src/main/resources/swift6/JSONValue.mustache
index 8d99b8271f52..d8653da01340 100644
--- a/modules/openapi-generator/src/main/resources/swift6/JSONValue.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/JSONValue.mustache
@@ -7,7 +7,7 @@
import Foundation
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum JSONValue: Sendable, Codable, Hashable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}enum JSONValue: Sendable, Codable, Hashable {
case string(String)
case int(Int)
case double(Double)
@@ -62,7 +62,7 @@ import Foundation
}
}
-extension JSONValue {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(_ value: String) {
self = .string(value)
}
@@ -97,7 +97,7 @@ extension JSONValue {
}
}
-extension JSONValue {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var isString: Bool {
if case .string = self { return true }
return false
@@ -134,7 +134,7 @@ extension JSONValue {
}
-extension JSONValue {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var stringValue: String? {
switch self {
case .string(let value):
@@ -186,7 +186,7 @@ extension JSONValue {
}
}
-extension JSONValue {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} subscript(key: String) -> JSONValue? {
return dictionaryValue?[key]
}
@@ -199,38 +199,38 @@ extension JSONValue {
}
}
-extension JSONValue: ExpressibleByStringLiteral, ExpressibleByStringInterpolation {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByStringLiteral, ExpressibleByStringInterpolation {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(stringLiteral value: StringLiteralType) {
self = .string(value)
}
}
-extension JSONValue: ExpressibleByIntegerLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByIntegerLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(integerLiteral value: IntegerLiteralType) {
self = .int(value)
}
}
-extension JSONValue: ExpressibleByFloatLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByFloatLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(floatLiteral value: FloatLiteralType) {
self = .double(value)
}
}
-extension JSONValue: ExpressibleByBooleanLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByBooleanLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(booleanLiteral value: BooleanLiteralType) {
self = .bool(value)
}
}
-extension JSONValue: ExpressibleByArrayLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByArrayLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(arrayLiteral elements: JSONValue...) {
self = .array(elements)
}
}
-extension JSONValue: ExpressibleByDictionaryLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByDictionaryLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(dictionaryLiteral elements: (String, JSONValue)...) {
var dict: [String: JSONValue] = [:]
for (key, value) in elements {
@@ -240,7 +240,7 @@ extension JSONValue: ExpressibleByDictionaryLiteral {
}
}
-extension JSONValue: ExpressibleByNilLiteral {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension JSONValue: ExpressibleByNilLiteral {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(nilLiteral: ()) {
self = .null
}
diff --git a/modules/openapi-generator/src/main/resources/swift6/Models.mustache b/modules/openapi-generator/src/main/resources/swift6/Models.mustache
index 7e7bb883922a..a5135bd8f26c 100644
--- a/modules/openapi-generator/src/main/resources/swift6/Models.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/Models.mustache
@@ -10,15 +10,15 @@ import FoundationNetworking
#endif{{#useAlamofire}}
import Alamofire{{/useAlamofire}}
-protocol ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}protocol ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable
}
/// An enum where the last case value can be used as a default catch-all.
-protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
where RawValue: Decodable, AllCases: BidirectionalCollection {}
-extension CaseIterableDefaultsLast {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension CaseIterableDefaultsLast {
/// Initializes an enum such that if a known raw value is found, then it is decoded.
/// Otherwise the last case is used.
/// - Parameter decoder: A decoder.
@@ -40,28 +40,28 @@ extension CaseIterableDefaultsLast {
/// Protocol for types used as oneOf variants, allowing the oneOf decoder to reject
/// a variant that only decoded successfully because CaseIterableDefaultsLast
/// silently accepted an unknown enum value.
-protocol UnknownCaseCheckable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}protocol UnknownCaseCheckable {
var containsUnknownDefaultOpenApiCase: Bool { get }
}
-extension UnknownCaseCheckable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension UnknownCaseCheckable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var containsUnknownDefaultOpenApiCase: Bool { false }
}
{{/enumUnknownDefaultCase}}
/// A flexible type that can be encoded (`.encodeNull` or `.encodeValue`)
/// or not encoded (`.encodeNothing`). Intended for request payloads.
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum NullEncodable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}enum NullEncodable {
case encodeNothing
case encodeNull
case encodeValue(Wrapped)
}
-extension NullEncodable: Equatable where Wrapped: Equatable {}
-extension NullEncodable: Hashable where Wrapped: Hashable {}
-extension NullEncodable: Sendable where Wrapped: Sendable {}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension NullEncodable: Equatable where Wrapped: Equatable {}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension NullEncodable: Hashable where Wrapped: Hashable {}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension NullEncodable: Sendable where Wrapped: Sendable {}
-extension NullEncodable: Codable where Wrapped: Codable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension NullEncodable: Codable where Wrapped: Codable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Wrapped.self) {
diff --git a/modules/openapi-generator/src/main/resources/swift6/OpenAPIDateWithoutTime.mustache b/modules/openapi-generator/src/main/resources/swift6/OpenAPIDateWithoutTime.mustache
index 2c98b8ed19c2..092ada5775e2 100644
--- a/modules/openapi-generator/src/main/resources/swift6/OpenAPIDateWithoutTime.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/OpenAPIDateWithoutTime.mustache
@@ -15,7 +15,7 @@ import Foundation
/// an appropriate padding in order to transform to GMT+0 which is the assumed timezone in ISO 8601.
/// When decoding, GMT+0 can be assumed (again: ISO8601) so there is no padding necessary and wrappedDate
/// can be used safely.
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct OpenAPIDateWithoutTime: Sendable, Codable, Hashable, Equatable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}struct OpenAPIDateWithoutTime: Sendable, Codable, Hashable, Equatable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let wrappedDate: Date
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let timezone: TimeZone
@@ -76,13 +76,13 @@ import Foundation
}
}
-extension OpenAPIDateWithoutTime: ParameterConvertible {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension OpenAPIDateWithoutTime: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return OpenISO8601DateFormatter.withoutTime.string(from: self.normalizedWrappedDate())
}
}
-extension OpenAPIDateWithoutTime: RawRepresentable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension OpenAPIDateWithoutTime: RawRepresentable {
public typealias RawValue = String
public init?(rawValue: String) {
if let date = OpenISO8601DateFormatter.withoutTime.date(from: rawValue) {
diff --git a/modules/openapi-generator/src/main/resources/swift6/OpenAPIMutex.mustache b/modules/openapi-generator/src/main/resources/swift6/OpenAPIMutex.mustache
index d7be0b6bd92e..24ef62fcf085 100644
--- a/modules/openapi-generator/src/main/resources/swift6/OpenAPIMutex.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/OpenAPIMutex.mustache
@@ -6,7 +6,7 @@
import Foundation
-internal final class OpenAPIMutex: @unchecked Sendable {
+internal {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}final class OpenAPIMutex: @unchecked Sendable {
private var _value: Value
private let lock = NSRecursiveLock()
diff --git a/modules/openapi-generator/src/main/resources/swift6/OpenISO8601DateFormatter.mustache b/modules/openapi-generator/src/main/resources/swift6/OpenISO8601DateFormatter.mustache
index fa2335d70c3f..5cb59ecb0dc5 100644
--- a/modules/openapi-generator/src/main/resources/swift6/OpenISO8601DateFormatter.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/OpenISO8601DateFormatter.mustache
@@ -8,7 +8,7 @@
import Foundation
// https://stackoverflow.com/a/50281094/976628
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class OpenISO8601DateFormatter: DateFormatter, @unchecked Sendable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}class OpenISO8601DateFormatter: DateFormatter, @unchecked Sendable {
static let withoutSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
diff --git a/modules/openapi-generator/src/main/resources/swift6/Validation.mustache b/modules/openapi-generator/src/main/resources/swift6/Validation.mustache
index adfb876f001b..ff686e8936ff 100644
--- a/modules/openapi-generator/src/main/resources/swift6/Validation.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/Validation.mustache
@@ -6,22 +6,22 @@
import Foundation
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct StringRule: Sendable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}struct StringRule: Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var minLength: Int?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var maxLength: Int?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var pattern: String?
}
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct NumericRule {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}struct NumericRule {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var minimum: T?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var exclusiveMinimum = false
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var maximum: T?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var exclusiveMaximum = false
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var multipleOf: T?
}
-extension NumericRule: Sendable where T: Sendable {}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension NumericRule: Sendable where T: Sendable {}
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct ArrayRule: Sendable {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}struct ArrayRule: Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var minItems: Int?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var maxItems: Int?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var uniqueItems: Bool
diff --git a/modules/openapi-generator/src/main/resources/swift6/model.mustache b/modules/openapi-generator/src/main/resources/swift6/model.mustache
index 3b9caaa08f97..f1f22d827b44 100644
--- a/modules/openapi-generator/src/main/resources/swift6/model.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/model.mustache
@@ -15,7 +15,7 @@ import {{{.}}}
@available(*, deprecated, renamed: "{{projectName}}API.{{classname}}")
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} typealias {{classname}} = {{projectName}}API.{{classname}}
-extension {{projectName}}API {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension {{projectName}}API {
{{/swiftUseApiNamespace}}
{{#description}}
@@ -28,9 +28,9 @@ extension {{projectName}}API {
{{#swiftUseApiNamespace}}
}
{{/swiftUseApiNamespace}}{{#models}}{{#model}}{{#vendorExtensions.x-swift-identifiable}}
-extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: Identifiable {}
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: Identifiable {}
{{/vendorExtensions.x-swift-identifiable}}{{#enumUnknownDefaultCase}}{{^vendorExtensions.x-is-one-of-interface}}{{^isArray}}{{^isEnum}}{{#hasEnums}}
-extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: UnknownCaseCheckable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: UnknownCaseCheckable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var containsUnknownDefaultOpenApiCase: Bool {
{{#allVars}}
{{#isEnum}}
@@ -80,7 +80,7 @@ extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{
}
}
{{/hasEnums}}{{/isEnum}}{{/isArray}}{{/vendorExtensions.x-is-one-of-interface}}{{#isEnum}}
-extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: UnknownCaseCheckable {
+{{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: UnknownCaseCheckable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var containsUnknownDefaultOpenApiCase: Bool {
self == .unknownDefaultOpenApi
}
diff --git a/modules/openapi-generator/src/main/resources/swift6/modelEnum.mustache b/modules/openapi-generator/src/main/resources/swift6/modelEnum.mustache
index 839ec0115dc4..a7bd0efffa5f 100644
--- a/modules/openapi-generator/src/main/resources/swift6/modelEnum.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/modelEnum.mustache
@@ -1,5 +1,5 @@
{{#additionalModelEnumAttributes}}{{{.}}}
-{{/additionalModelEnumAttributes}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{dataType}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{/enumUnknownDefaultCase}} {
+{{/additionalModelEnumAttributes}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}enum {{classname}}: {{dataType}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{/enumUnknownDefaultCase}} {
{{#allowableValues}}
{{#enumVars}}
{{#enumDescription}}
diff --git a/modules/openapi-generator/src/main/resources/swift6/modelObject.mustache b/modules/openapi-generator/src/main/resources/swift6/modelObject.mustache
index 445826d40146..fa45051c9947 100644
--- a/modules/openapi-generator/src/main/resources/swift6/modelObject.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/modelObject.mustache
@@ -1,6 +1,6 @@
{{#additionalModelObjectAttributes}}{{{.}}}
-{{/additionalModelObjectAttributes}}{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#vendorExtensions.x-swift-use-class}}final class{{/vendorExtensions.x-swift-use-class}}{{^vendorExtensions.x-swift-use-class}}struct{{/vendorExtensions.x-swift-use-class}} {{{classname}}}: {{^vendorExtensions.x-swift-use-class}}Sendable, {{/vendorExtensions.x-swift-use-class}}{{#vendorExtensions.x-swift-unchecked-sendable}}@unchecked Sendable, {{/vendorExtensions.x-swift-unchecked-sendable}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
-{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class {{classname}}: NSObject, Codable, @unchecked Sendable {
+{{/additionalModelObjectAttributes}}{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}{{#vendorExtensions.x-swift-use-class}}final class{{/vendorExtensions.x-swift-use-class}}{{^vendorExtensions.x-swift-use-class}}struct{{/vendorExtensions.x-swift-use-class}} {{{classname}}}: {{^vendorExtensions.x-swift-use-class}}Sendable, {{/vendorExtensions.x-swift-use-class}}{{#vendorExtensions.x-swift-unchecked-sendable}}@unchecked Sendable, {{/vendorExtensions.x-swift-unchecked-sendable}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
+{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}final class {{classname}}: NSObject, Codable, @unchecked Sendable {
{{/objcCompatible}}
{{#allVars}}
diff --git a/modules/openapi-generator/src/main/resources/swift6/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/swift6/modelOneOf.mustache
index eeb9b2129561..666f382e8133 100644
--- a/modules/openapi-generator/src/main/resources/swift6/modelOneOf.mustache
+++ b/modules/openapi-generator/src/main/resources/swift6/modelOneOf.mustache
@@ -1,4 +1,4 @@
-{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}}{{/useVapor}} {
+{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#nonisolatedModels}}nonisolated {{/nonisolatedModels}}enum {{classname}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}}{{/useVapor}} {
{{#oneOf}}
case type{{#transformArrayType}}{{.}}{{/transformArrayType}}({{.}})
{{/oneOf}}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/Swift6ClientCodegenOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/Swift6ClientCodegenOptionsProvider.java
index e470c5646c00..b2d419ba03e0 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/Swift6ClientCodegenOptionsProvider.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/Swift6ClientCodegenOptionsProvider.java
@@ -47,6 +47,7 @@ public class Swift6ClientCodegenOptionsProvider implements OptionsProvider {
public static final String USE_BACKTICKS_ESCAPES_VALUE = "false";
public static final String GENERATE_MODEL_ADDITIONAL_PROPERTIES_VALUE = "true";
public static final String HASHABLE_MODELS_VALUE = "true";
+ public static final String NONISOLATED_MODELS_VALUE = "true";
public static final String IDENTIFIABLE_MODELS_VALUE = "true";
public static final String USE_PARAMETER_CONVERTIBLE_VALUE = "true";
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
@@ -102,6 +103,7 @@ public Map createOptions() {
GENERATE_MODEL_ADDITIONAL_PROPERTIES_VALUE)
.put(Swift6ClientCodegen.HASHABLE_MODELS, HASHABLE_MODELS_VALUE)
.put(Swift6ClientCodegen.IDENTIFIABLE_MODELS, IDENTIFIABLE_MODELS_VALUE)
+ .put(Swift6ClientCodegen.NONISOLATED_MODELS, NONISOLATED_MODELS_VALUE)
.put(Swift6ClientCodegen.USE_PARAMETER_CONVERTIBLE, USE_PARAMETER_CONVERTIBLE_VALUE)
.put(Swift6ClientCodegen.MAP_FILE_BINARY_TO_DATA, "false")
.put(Swift6ClientCodegen.USE_CUSTOM_DATE_WITHOUT_TIME, "false")
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenOptionsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenOptionsTest.java
index 90b95cced876..20e9d0c8c94b 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenOptionsTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenOptionsTest.java
@@ -56,6 +56,7 @@ protected void verifyOptions() {
Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.GENERATE_MODEL_ADDITIONAL_PROPERTIES_VALUE));
verify(clientCodegen).setHashableModels(Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.HASHABLE_MODELS_VALUE));
verify(clientCodegen).setIdentifiableModels(Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.IDENTIFIABLE_MODELS_VALUE));
+ verify(clientCodegen).setNonisolatedModels(Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.NONISOLATED_MODELS_VALUE));
verify(clientCodegen)
.setEnumUnknownDefaultCase(Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.ENUM_UNKNOWN_DEFAULT_CASE_VALUE));
verify(clientCodegen).setApiStaticMethod(Boolean.parseBoolean(Swift6ClientCodegenOptionsProvider.API_STATIC_METHOD_VALUE));
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java
index 27c6f151381e..0d657279af28 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java
@@ -77,6 +77,90 @@ public void testRecursiveModelsBecomeClasses() throws IOException {
TestUtils.assertFileContains(models.resolve("Base.swift"), "public struct Base: Sendable,");
}
+ @Test(description = "nonisolatedModels marks models and their supporting declarations nonisolated")
+ public void testNonisolatedModels() throws IOException {
+ Path sources = generateSwift6("src/test/resources/3_0/swift/recursive-models.yaml",
+ Swift6ClientCodegen.NONISOLATED_MODELS, true);
+ Path models = sources.resolve("Models");
+ Path infrastructure = sources.resolve("Infrastructure");
+ // structs, classes and the extensions emitted next to them
+ TestUtils.assertFileContains(models.resolve("Category.swift"), "public nonisolated struct Category: Sendable,");
+ TestUtils.assertFileContains(models.resolve("ContactInfo.swift"), "public nonisolated final class ContactInfo: @unchecked Sendable,");
+ // the protocols and helper types that models conform to or store
+ TestUtils.assertFileContains(infrastructure.resolve("Models.swift"), "nonisolated protocol ParameterConvertible {");
+ TestUtils.assertFileContains(infrastructure.resolve("Models.swift"), "nonisolated protocol CaseIterableDefaultsLast:");
+ TestUtils.assertFileContains(infrastructure.resolve("Models.swift"), "public nonisolated enum NullEncodable {");
+ TestUtils.assertFileContains(infrastructure.resolve("Models.swift"), "nonisolated extension NullEncodable: Codable where Wrapped: Codable {");
+ TestUtils.assertFileContains(infrastructure.resolve("JSONValue.swift"), "public nonisolated enum JSONValue: Sendable, Codable, Hashable {");
+ TestUtils.assertFileContains(infrastructure.resolve("Validation.swift"), "public nonisolated struct StringRule: Sendable {");
+ TestUtils.assertFileContains(infrastructure.resolve("Extensions.swift"), "nonisolated extension String: @retroactive CodingKey {");
+ TestUtils.assertFileContains(infrastructure.resolve("Extensions.swift"), "nonisolated extension RawRepresentable where RawValue: ParameterConvertible {");
+ TestUtils.assertFileContains(infrastructure.resolve("CodableHelper.swift"), "open nonisolated class CodableHelper: @unchecked Sendable {");
+ TestUtils.assertFileContains(infrastructure.resolve("OpenAPIMutex.swift"), "internal nonisolated final class OpenAPIMutex: @unchecked Sendable {");
+ TestUtils.assertFileContains(infrastructure.resolve("OpenISO8601DateFormatter.swift"), "public nonisolated class OpenISO8601DateFormatter: DateFormatter, @unchecked Sendable {");
+
+ // the extensions emitted next to models (Identifiable, UnknownCaseCheckable)
+ Path petstoreSources = generateSwift6("src/test/resources/3_0/petstore.yaml",
+ Swift6ClientCodegen.NONISOLATED_MODELS, true,
+ CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, true);
+ Path pet = petstoreSources.resolve("Models/Pet.swift");
+ TestUtils.assertFileContains(pet, "public nonisolated struct Pet: Sendable,");
+ TestUtils.assertFileContains(pet, "nonisolated extension Pet: Identifiable {}");
+ TestUtils.assertFileContains(pet, "nonisolated extension Pet: UnknownCaseCheckable {");
+ TestUtils.assertFileContains(petstoreSources.resolve("Infrastructure/Models.swift"), "nonisolated protocol UnknownCaseCheckable {");
+ TestUtils.assertFileContains(petstoreSources.resolve("Infrastructure/Models.swift"), "nonisolated extension CaseIterableDefaultsLast {");
+ // inline enums are nested in the model and inherit its isolation, so they are not marked
+ TestUtils.assertFileContains(pet, " public enum Status: String, Sendable, Codable, CaseIterable, CaseIterableDefaultsLast {");
+ TestUtils.assertFileNotContains(pet, "nonisolated enum");
+
+ // top-level enum models and their UnknownCaseCheckable extension
+ Path enumModels = generateSwift6("src/test/resources/3_0/enum-description.yaml",
+ Swift6ClientCodegen.NONISOLATED_MODELS, true,
+ CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, true).resolve("Models");
+ TestUtils.assertFileContains(enumModels.resolve("ModelType.swift"),
+ "public nonisolated enum ModelType: String, Sendable, Codable, CaseIterable, CaseIterableDefaultsLast {");
+ TestUtils.assertFileContains(enumModels.resolve("ModelType.swift"), "nonisolated extension ModelType: UnknownCaseCheckable {");
+
+ // oneOf models are generated as enums
+ Path oneOfModels = generateSwift6("src/test/resources/3_0/oneOf.yaml",
+ Swift6ClientCodegen.NONISOLATED_MODELS, true).resolve("Models");
+ TestUtils.assertFileContains(oneOfModels.resolve("Fruit.swift"), "public nonisolated enum Fruit: Sendable, Codable, Hashable {");
+ }
+
+ @Test(description = "nonisolatedModels also marks objcCompatible model classes nonisolated")
+ public void testNonisolatedModelsObjcCompatible() throws IOException {
+ Path models = generateSwift6("src/test/resources/3_0/swift/recursive-models.yaml",
+ Swift6ClientCodegen.NONISOLATED_MODELS, true,
+ Swift6ClientCodegen.OBJC_COMPATIBLE, true).resolve("Models");
+ TestUtils.assertFileContains(models.resolve("Category.swift"),
+ "@objcMembers public nonisolated final class Category: NSObject, Codable, @unchecked Sendable {");
+ }
+
+ private static Path generateSwift6(String inputSpec, Object... additionalProperties) throws IOException {
+ Path target = Files.createTempDirectory("test");
+ target.toFile().deleteOnExit();
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("swift6")
+ .setInputSpec(inputSpec)
+ .setOutputDir(target.toAbsolutePath().toString());
+ for (int i = 0; i < additionalProperties.length; i += 2) {
+ configurator.addAdditionalProperty((String) additionalProperties[i], additionalProperties[i + 1]);
+ }
+ new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
+ return target.resolve("Sources/OpenAPIClient");
+ }
+
+ @Test(description = "nonisolatedModels is off by default")
+ public void testNonisolatedModelsDefaultsOff() throws IOException {
+ Path sources = generateSwift6("src/test/resources/3_0/swift/recursive-models.yaml");
+ Path infrastructure = sources.resolve("Infrastructure");
+ TestUtils.assertFileNotContains(sources.resolve("Models/Category.swift"), "nonisolated");
+ TestUtils.assertFileNotContains(infrastructure.resolve("Models.swift"), "nonisolated");
+ TestUtils.assertFileNotContains(infrastructure.resolve("JSONValue.swift"), "nonisolated");
+ TestUtils.assertFileNotContains(infrastructure.resolve("Extensions.swift"), "nonisolated");
+ TestUtils.assertFileNotContains(infrastructure.resolve("CodableHelper.swift"), "nonisolated");
+ }
+
@Test(enabled = true)
public void testCapitalizedReservedWord() throws Exception {
Assert.assertEquals(swiftCodegen.toEnumVarName("AS", null), "_as");
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift
index 7d6f7a6fd1bd..7c9fe2e84e7a 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift
@@ -7,7 +7,7 @@
import Foundation
-open class CodableHelper: @unchecked Sendable {
+open nonisolated class CodableHelper: @unchecked Sendable {
// MARK: - Private state
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Extensions.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Extensions.swift
index 31258876af84..93e263422a9f 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Extensions.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Extensions.swift
@@ -9,53 +9,53 @@ import Foundation
import FoundationNetworking
#endif
-extension Bool: ParameterConvertible {
+nonisolated extension Bool: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Float: ParameterConvertible {
+nonisolated extension Float: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int: ParameterConvertible {
+nonisolated extension Int: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int32: ParameterConvertible {
+nonisolated extension Int32: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Int64: ParameterConvertible {
+nonisolated extension Int64: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Double: ParameterConvertible {
+nonisolated extension Double: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension Decimal: ParameterConvertible {
+nonisolated extension Decimal: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension String: ParameterConvertible {
+nonisolated extension String: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension URL: ParameterConvertible {
+nonisolated extension URL: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension UUID: ParameterConvertible {
+nonisolated extension UUID: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}
-extension RawRepresentable where RawValue: ParameterConvertible {
+nonisolated extension RawRepresentable where RawValue: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
rawValue.asParameter(codableHelper: codableHelper)
}
}
-private func encodeIfPossible(_ object: T, codableHelper: CodableHelper) -> any Sendable {
+private nonisolated func encodeIfPossible(_ object: T, codableHelper: CodableHelper) -> any Sendable {
if let encodableObject = object as? ParameterConvertible {
return encodableObject.asParameter(codableHelper: codableHelper)
} else {
@@ -63,19 +63,19 @@ private func encodeIfPossible(_ object: T, codableHelper: CodableHe
}
}
-extension Array where Element: Sendable {
+nonisolated extension Array where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.map { encodeIfPossible($0, codableHelper: codableHelper) }
}
}
-extension Set where Element: Sendable {
+nonisolated extension Set where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return Array(self).asParameter(codableHelper: codableHelper)
}
}
-extension Dictionary where Key: Sendable, Value: Sendable {
+nonisolated extension Dictionary where Key: Sendable, Value: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
var dictionary = [Key: any Sendable]()
for (key, value) in self {
@@ -85,19 +85,19 @@ extension Dictionary where Key: Sendable, Value: Sendable {
}
}
-extension Data: ParameterConvertible {
+nonisolated extension Data: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.base64EncodedString(options: Data.Base64EncodingOptions())
}
}
-extension Date: ParameterConvertible {
+nonisolated extension Date: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return codableHelper.dateFormatter.string(from: self)
}
}
-extension String: @retroactive CodingKey {
+nonisolated extension String: @retroactive CodingKey {
public var stringValue: String {
return self
@@ -117,7 +117,7 @@ extension String: @retroactive CodingKey {
}
-extension KeyedEncodingContainerProtocol {
+nonisolated extension KeyedEncodingContainerProtocol {
public mutating func encodeArray(_ values: [T], forKey key: Self.Key) throws where T: Encodable {
var arrayContainer = nestedUnkeyedContainer(forKey: key)
@@ -159,7 +159,7 @@ extension KeyedEncodingContainerProtocol {
}
}
-extension KeyedDecodingContainerProtocol {
+nonisolated extension KeyedDecodingContainerProtocol {
public func decodeArray(_ type: T.Type, forKey key: Self.Key) throws -> [T] where T: Decodable {
var tmpArray = [T]()
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONValue.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONValue.swift
index 8eb952c7bfca..b0d24d5dc815 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONValue.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONValue.swift
@@ -7,7 +7,7 @@
import Foundation
-public enum JSONValue: Sendable, Codable, Hashable {
+public nonisolated enum JSONValue: Sendable, Codable, Hashable {
case string(String)
case int(Int)
case double(Double)
@@ -62,7 +62,7 @@ public enum JSONValue: Sendable, Codable, Hashable {
}
}
-extension JSONValue {
+nonisolated extension JSONValue {
public init(_ value: String) {
self = .string(value)
}
@@ -97,7 +97,7 @@ extension JSONValue {
}
}
-extension JSONValue {
+nonisolated extension JSONValue {
public var isString: Bool {
if case .string = self { return true }
return false
@@ -134,7 +134,7 @@ extension JSONValue {
}
-extension JSONValue {
+nonisolated extension JSONValue {
public var stringValue: String? {
switch self {
case .string(let value):
@@ -186,7 +186,7 @@ extension JSONValue {
}
}
-extension JSONValue {
+nonisolated extension JSONValue {
public subscript(key: String) -> JSONValue? {
return dictionaryValue?[key]
}
@@ -199,38 +199,38 @@ extension JSONValue {
}
}
-extension JSONValue: ExpressibleByStringLiteral, ExpressibleByStringInterpolation {
+nonisolated extension JSONValue: ExpressibleByStringLiteral, ExpressibleByStringInterpolation {
public init(stringLiteral value: StringLiteralType) {
self = .string(value)
}
}
-extension JSONValue: ExpressibleByIntegerLiteral {
+nonisolated extension JSONValue: ExpressibleByIntegerLiteral {
public init(integerLiteral value: IntegerLiteralType) {
self = .int(value)
}
}
-extension JSONValue: ExpressibleByFloatLiteral {
+nonisolated extension JSONValue: ExpressibleByFloatLiteral {
public init(floatLiteral value: FloatLiteralType) {
self = .double(value)
}
}
-extension JSONValue: ExpressibleByBooleanLiteral {
+nonisolated extension JSONValue: ExpressibleByBooleanLiteral {
public init(booleanLiteral value: BooleanLiteralType) {
self = .bool(value)
}
}
-extension JSONValue: ExpressibleByArrayLiteral {
+nonisolated extension JSONValue: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: JSONValue...) {
self = .array(elements)
}
}
-extension JSONValue: ExpressibleByDictionaryLiteral {
+nonisolated extension JSONValue: ExpressibleByDictionaryLiteral {
public init(dictionaryLiteral elements: (String, JSONValue)...) {
var dict: [String: JSONValue] = [:]
for (key, value) in elements {
@@ -240,7 +240,7 @@ extension JSONValue: ExpressibleByDictionaryLiteral {
}
}
-extension JSONValue: ExpressibleByNilLiteral {
+nonisolated extension JSONValue: ExpressibleByNilLiteral {
public init(nilLiteral: ()) {
self = .null
}
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift
index e98056ea6658..143346e8a061 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift
@@ -9,15 +9,15 @@ import Foundation
import FoundationNetworking
#endif
-protocol ParameterConvertible {
+nonisolated protocol ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable
}
/// An enum where the last case value can be used as a default catch-all.
-protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
+nonisolated protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
where RawValue: Decodable, AllCases: BidirectionalCollection {}
-extension CaseIterableDefaultsLast {
+nonisolated extension CaseIterableDefaultsLast {
/// Initializes an enum such that if a known raw value is found, then it is decoded.
/// Otherwise the last case is used.
/// - Parameter decoder: A decoder.
@@ -37,17 +37,17 @@ extension CaseIterableDefaultsLast {
/// A flexible type that can be encoded (`.encodeNull` or `.encodeValue`)
/// or not encoded (`.encodeNothing`). Intended for request payloads.
-public enum NullEncodable {
+public nonisolated enum NullEncodable {
case encodeNothing
case encodeNull
case encodeValue(Wrapped)
}
-extension NullEncodable: Equatable where Wrapped: Equatable {}
-extension NullEncodable: Hashable where Wrapped: Hashable {}
-extension NullEncodable: Sendable where Wrapped: Sendable {}
+nonisolated extension NullEncodable: Equatable where Wrapped: Equatable {}
+nonisolated extension NullEncodable: Hashable where Wrapped: Hashable {}
+nonisolated extension NullEncodable: Sendable where Wrapped: Sendable {}
-extension NullEncodable: Codable where Wrapped: Codable {
+nonisolated extension NullEncodable: Codable where Wrapped: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Wrapped.self) {
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenAPIMutex.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenAPIMutex.swift
index d7be0b6bd92e..fa18460e49af 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenAPIMutex.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenAPIMutex.swift
@@ -6,7 +6,7 @@
import Foundation
-internal final class OpenAPIMutex: @unchecked Sendable {
+internal nonisolated final class OpenAPIMutex: @unchecked Sendable {
private var _value: Value
private let lock = NSRecursiveLock()
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenISO8601DateFormatter.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenISO8601DateFormatter.swift
index 8275bd0861a8..796fb78966d3 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenISO8601DateFormatter.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/OpenISO8601DateFormatter.swift
@@ -8,7 +8,7 @@
import Foundation
// https://stackoverflow.com/a/50281094/976628
-public class OpenISO8601DateFormatter: DateFormatter, @unchecked Sendable {
+public nonisolated class OpenISO8601DateFormatter: DateFormatter, @unchecked Sendable {
static let withoutSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Validation.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Validation.swift
index 11b7ac6a90be..2b7c83890016 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Validation.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Validation.swift
@@ -6,22 +6,22 @@
import Foundation
-public struct StringRule: Sendable {
+public nonisolated struct StringRule: Sendable {
public var minLength: Int?
public var maxLength: Int?
public var pattern: String?
}
-public struct NumericRule {
+public nonisolated struct NumericRule {
public var minimum: T?
public var exclusiveMinimum = false
public var maximum: T?
public var exclusiveMaximum = false
public var multipleOf: T?
}
-extension NumericRule: Sendable where T: Sendable {}
+nonisolated extension NumericRule: Sendable where T: Sendable {}
-public struct ArrayRule: Sendable {
+public nonisolated struct ArrayRule: Sendable {
public var minItems: Int?
public var maxItems: Int?
public var uniqueItems: Bool
diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Models/Banana.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Models/Banana.swift
index b693c50fb9e5..ec225eec38e4 100644
--- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Models/Banana.swift
+++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Models/Banana.swift
@@ -7,7 +7,7 @@
import Foundation
-public struct Banana: Sendable, Codable, Hashable {
+public nonisolated struct Banana: Sendable, Codable, Hashable {
public static let countRule = NumericRule(minimum: 10, exclusiveMinimum: true, maximum: 100, exclusiveMaximum: true, multipleOf: 5)
public static let idsRule = ArrayRule(minItems: 1, maxItems: 10, uniqueItems: false)