Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .swift-format
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"prioritizeKeepingFunctionOutputTogether" : false,
"respectsExistingLineBreaks" : true,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AllPublicDeclarationsHaveDocumentation" : true,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
Expand Down Expand Up @@ -50,7 +50,7 @@
"UseSynthesizedInitializer" : false,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
"ValidateDocumentationComments" : true
},
"spacesAroundRangeFormationOperators" : false,
"tabWidth" : 8,
Expand Down
22 changes: 19 additions & 3 deletions Sources/OpenAPIRuntime/Base/Acceptable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public struct QualityValue: Sendable, Hashable {

/// Creates a new quality value from the provided floating-point number.
///
/// - Precondition: The value must be between 0.0 and 1.0, inclusive.
/// - Parameter doubleValue: The floating-point number representing the quality value.
/// - Precondition: The `doubleValue` must be between 0.0 and 1.0, inclusive.
public init(doubleValue: Double) {
precondition(
doubleValue >= 0.0 && doubleValue <= 1.0,
Expand All @@ -51,19 +52,27 @@ public struct QualityValue: Sendable, Hashable {
}

extension QualityValue: RawRepresentable {
/// Creates a new `QualityValue` instance from a raw string value.
///
/// - Parameter rawValue: A string representing the quality value.
public init?(rawValue: String) {
guard let doubleValue = Double(rawValue) else {
return nil
}
self.init(doubleValue: doubleValue)
}

/// The raw string representation of the `QualityValue`.
public var rawValue: String {
String(format: "%0.3f", doubleValue)
}
}

extension QualityValue: ExpressibleByIntegerLiteral {
/// Creates a new `QualityValue` instance from an integer literal value.
///
/// - Parameter value: An integer literal value representing the quality value.
/// - Precondition: The `integerLiteral` must be between 0.0 and 1.0, inclusive.
public init(integerLiteral value: UInt16) {
precondition(
value >= 0 && value <= 1,
Expand All @@ -74,6 +83,9 @@ extension QualityValue: ExpressibleByIntegerLiteral {
}

extension QualityValue: ExpressibleByFloatLiteral {
/// Creates a new `QualityValue` instance from a floating-point literal value.
///
/// - Parameter value: A floating-point literal value representing the quality value.
public init(floatLiteral value: Double) {
self.init(doubleValue: value)
}
Expand Down Expand Up @@ -106,10 +118,10 @@ public struct AcceptHeaderContentType<ContentType: AcceptableProtocol>: Sendable
public var quality: QualityValue

/// Creates a new content type from the provided parameters.
///
/// - Parameters:
/// - value: The value representing the content type.
/// - contentType: The value representing the content type.
/// - quality: The quality of the content type, between 0.0 and 1.0.
/// - Precondition: Quality must be in the range 0.0 and 1.0 inclusive.
public init(contentType: ContentType, quality: QualityValue = 1.0) {
self.quality = quality
self.contentType = contentType
Expand All @@ -123,6 +135,9 @@ public struct AcceptHeaderContentType<ContentType: AcceptableProtocol>: Sendable
}

extension AcceptHeaderContentType: RawRepresentable {
/// Initializes an `AcceptHeaderContentType` instance from its raw string value.
///
/// - Parameter rawValue: The raw string value representing the content type.
public init?(rawValue: String) {
guard let validMimeType = OpenAPIMIMEType(rawValue) else {
// Invalid MIME type.
Expand All @@ -145,6 +160,7 @@ extension AcceptHeaderContentType: RawRepresentable {
self.init(contentType: typeAndSubtype, quality: quality)
}

/// The raw representation of the content negotiation as a MIME type string.
public var rawValue: String {
contentType.rawValue + (quality.isDefault ? "" : "; q=\(quality.rawValue)")
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/OpenAPIRuntime/Base/Base64EncodedData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public struct Base64EncodedData: Sendable, Hashable {
}

extension Base64EncodedData: Codable {
/// Initializes a `Base64EncodedData` instance by decoding a base64-encoded string.
///
/// - Parameter decoder: The decoder from which to decode the base64-encoded string.
/// - Throws: `RuntimeError.invalidBase64String`: If the provided string could not be successfully decoded as base64 data.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
let base64EncodedString = try container.decode(String.self)
Expand All @@ -75,6 +79,10 @@ extension Base64EncodedData: Codable {
self.init(data: ArraySlice(data))
}

/// Encodes the binary data as a base64-encoded string.
///
/// - Parameter encoder: The encoder to which the base64-encoded string is written.
/// - Throws: An error if the binary data cannot be successfully encoded as a base64 string.
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()

Expand Down
22 changes: 22 additions & 0 deletions Sources/OpenAPIRuntime/Base/OpenAPIMIMEType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public struct OpenAPIMIMEType: Equatable {
/// A concrete value, spelled as `type/subtype`.
case concrete(type: String, subtype: String)

/// Compares two MIME type kinds for equality.
///
/// - Parameters:
/// - lhs: The left-hand side MIME type kind.
/// - rhs: The right-hand side MIME type kind.
///
/// - Returns: `true` if the MIME type kinds are equal, otherwise `false`.
public static func == (lhs: Kind, rhs: Kind) -> Bool {
switch (lhs, rhs) {
case (.any, .any):
Expand Down Expand Up @@ -59,6 +66,13 @@ public struct OpenAPIMIMEType: Equatable {
self.parameters = parameters
}

/// Compares two MIME types for equality.
///
/// - Parameters:
/// - lhs: The left-hand side MIME type.
/// - rhs: The right-hand side MIME type.
///
/// - Returns: `true` if the MIME types are equal, otherwise `false`.
public static func == (lhs: OpenAPIMIMEType, rhs: OpenAPIMIMEType) -> Bool {
guard lhs.kind == rhs.kind else {
return false
Expand All @@ -85,6 +99,9 @@ public struct OpenAPIMIMEType: Equatable {
}

extension OpenAPIMIMEType.Kind: LosslessStringConvertible {
/// Initializes a MIME type kind from a string description.
///
/// - Parameter description: A string description of the MIME type kind.
public init?(_ description: String) {
let typeAndSubtype =
description
Expand All @@ -106,6 +123,7 @@ extension OpenAPIMIMEType.Kind: LosslessStringConvertible {
}
}

/// A textual representation of the MIME type kind.
public var description: String {
switch self {
case .any:
Expand All @@ -119,6 +137,9 @@ extension OpenAPIMIMEType.Kind: LosslessStringConvertible {
}

extension OpenAPIMIMEType: LosslessStringConvertible {
/// Initializes an `OpenAPIMIMEType` instance based on a string description.
///
/// - Parameter description: A string description of the MIME.
public init?(_ description: String) {
var components =
description
Expand Down Expand Up @@ -157,6 +178,7 @@ extension OpenAPIMIMEType: LosslessStringConvertible {
)
}

/// A string description of the MIME type.
public var description: String {
([kind.description]
+ parameters
Expand Down
68 changes: 68 additions & 0 deletions Sources/OpenAPIRuntime/Base/OpenAPIValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ public struct OpenAPIValueContainer: Codable, Hashable, Sendable {

// MARK: Decodable

/// Initializes an `OpenAPIValueContainer` by decoding it from a decoder.
///
/// - Parameter decoder: The decoder to read data from.
/// - Throws: An error if the decoding process encounters issues or if the data is corrupted.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
Expand All @@ -124,6 +128,10 @@ public struct OpenAPIValueContainer: Codable, Hashable, Sendable {

// MARK: Encodable

/// Encodes the `OpenAPIValueContainer` and writes it to an encoder.
///
/// - Parameter encoder: The encoder to which the value should be encoded.
/// - Throws: An error if the encoding process encounters issues or if the value is invalid.
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
guard let value = value else {
Expand Down Expand Up @@ -153,6 +161,12 @@ public struct OpenAPIValueContainer: Codable, Hashable, Sendable {

// MARK: Equatable

/// Compares two `OpenAPIValueContainer` instances for equality.
///
/// - Parameters:
/// - lhs: The left-hand side `OpenAPIValueContainer` to compare.
/// - rhs: The right-hand side `OpenAPIValueContainer` to compare.
/// - Returns: `true` if the two instances are equal, `false` otherwise.
public static func == (lhs: OpenAPIValueContainer, rhs: OpenAPIValueContainer) -> Bool {
switch (lhs.value, rhs.value) {
case (nil, nil), is (Void, Void):
Expand Down Expand Up @@ -201,6 +215,9 @@ public struct OpenAPIValueContainer: Codable, Hashable, Sendable {

// MARK: Hashable

/// Hashes the `OpenAPIValueContainer` instance into a hasher.
///
/// - Parameter hasher: The hasher used to compute the hash value.
public func hash(into hasher: inout Hasher) {
switch value {
case let value as Bool:
Expand All @@ -227,30 +244,45 @@ public struct OpenAPIValueContainer: Codable, Hashable, Sendable {
}

extension OpenAPIValueContainer: ExpressibleByBooleanLiteral {
/// Creates an `OpenAPIValueContainer` with the provided boolean value.
///
/// - Parameter value: The boolean value to store in the container.
public init(booleanLiteral value: BooleanLiteralType) {
self.init(validatedValue: value)
}
}

extension OpenAPIValueContainer: ExpressibleByStringLiteral {
/// Creates an `OpenAPIValueContainer` with the provided string value.
///
/// - Parameter value: The string value to store in the container.
public init(stringLiteral value: String) {
self.init(validatedValue: value)
}
}

extension OpenAPIValueContainer: ExpressibleByNilLiteral {
/// Creates an `OpenAPIValueContainer` with a `nil` value.
///
/// - Parameter nilLiteral: The `nil` literal.
public init(nilLiteral: ()) {
self.init(validatedValue: nil)
}
}

extension OpenAPIValueContainer: ExpressibleByIntegerLiteral {
/// Creates an `OpenAPIValueContainer` with the provided integer value.
///
/// - Parameter value: The integer value to store in the container.
public init(integerLiteral value: Int) {
self.init(validatedValue: value)
}
}

extension OpenAPIValueContainer: ExpressibleByFloatLiteral {
/// Creates an `OpenAPIValueContainer` with the provided floating-point value.
///
/// - Parameter value: The floating-point value to store in the container.
public init(floatLiteral value: Double) {
self.init(validatedValue: value)
}
Expand Down Expand Up @@ -317,6 +349,10 @@ public struct OpenAPIObjectContainer: Codable, Hashable, Sendable {

// MARK: Decodable

/// Creates an `OpenAPIValueContainer` by decoding it from a single-value container in a given decoder.
///
/// - Parameter decoder: The decoder used to decode the container.
/// - Throws: An error if the decoding process encounters an issue or if the data does not match the expected format.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
let item = try container.decode([String: OpenAPIValueContainer].self)
Expand All @@ -325,13 +361,24 @@ public struct OpenAPIObjectContainer: Codable, Hashable, Sendable {

// MARK: Encodable

/// Encodes the `OpenAPIValueContainer` into a format that can be stored or transmitted via the given encoder.
///
/// - Parameter encoder: The encoder used to perform the encoding.
/// - Throws: An error if the encoding process encounters an issue or if the data does not match the expected format.
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value.mapValues(OpenAPIValueContainer.init(validatedValue:)))
}

// MARK: Equatable

/// Compares two `OpenAPIObjectContainer` instances for equality by comparing their inner key-value dictionaries.
///
/// - Parameters:
/// - lhs: The left-hand side `OpenAPIObjectContainer` to compare.
/// - rhs: The right-hand side `OpenAPIObjectContainer` to compare.
///
/// - Returns: `true` if the `OpenAPIObjectContainer` instances are equal, `false` otherwise.
public static func == (lhs: OpenAPIObjectContainer, rhs: OpenAPIObjectContainer) -> Bool {
let lv = lhs.value
let rv = rhs.value
Expand All @@ -352,6 +399,9 @@ public struct OpenAPIObjectContainer: Codable, Hashable, Sendable {

// MARK: Hashable

/// Hashes the `OpenAPIObjectContainer` instance into the provided `Hasher`.
///
/// - Parameter hasher: The `Hasher` into which the hash value is combined.
public func hash(into hasher: inout Hasher) {
for (key, itemValue) in value {
hasher.combine(key)
Expand Down Expand Up @@ -414,12 +464,17 @@ public struct OpenAPIArrayContainer: Codable, Hashable, Sendable {
/// Returns the specified value cast to an array of supported values.
/// - Parameter value: An array with untyped values.
/// - Returns: A cast value if values are supported, nil otherwise.
/// - Throws: An error if casting to supported values fails for any element.
static func tryCast(_ value: [(any Sendable)?]) throws -> [(any Sendable)?] {
return try value.map(OpenAPIValueContainer.tryCast(_:))
}

// MARK: Decodable

/// Initializes a new instance by decoding a validated array of values from a decoder.
///
/// - Parameter decoder: The decoder to use for decoding the array of values.
/// - Throws: An error if the decoding process fails or if the decoded values cannot be validated.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
let item = try container.decode([OpenAPIValueContainer].self)
Expand All @@ -428,13 +483,23 @@ public struct OpenAPIArrayContainer: Codable, Hashable, Sendable {

// MARK: Encodable

/// Encodes the array of validated values and stores the result in the given encoder.
///
/// - Parameter encoder: The encoder to use for encoding the array of values.
/// - Throws: An error if the encoding process fails.
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value.map(OpenAPIValueContainer.init(validatedValue:)))
}

// MARK: Equatable

/// Compares two `OpenAPIArrayContainer` instances for equality.
///
/// - Parameters:
/// - lhs: The left-hand side `OpenAPIArrayContainer` to compare.
/// - rhs: The right-hand side `OpenAPIArrayContainer` to compare.
/// - Returns: `true` if the two `OpenAPIArrayContainer` instances are equal, `false` otherwise.
public static func == (lhs: OpenAPIArrayContainer, rhs: OpenAPIArrayContainer) -> Bool {
let lv = lhs.value
let rv = rhs.value
Expand All @@ -449,6 +514,9 @@ public struct OpenAPIArrayContainer: Codable, Hashable, Sendable {

// MARK: Hashable

/// Hashes the `OpenAPIArrayContainer` instance into a hasher.
///
/// - Parameter hasher: The hasher used to compute the hash value.
public func hash(into hasher: inout Hasher) {
for item in value {
hasher.combine(OpenAPIValueContainer(validatedValue: item))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
///
/// There should be no runtime impact in release builds, as the function is inlined and
/// has no executable code.
/// - Parameter value: The value for which you want to suppress "variable was never mutated, change to let" warnings.
@_spi(Generated)
@inline(__always)
public func suppressMutabilityWarning<T>(_ value: inout T) {}
Expand All @@ -38,6 +39,7 @@ public func suppressMutabilityWarning<T>(_ value: inout T) {}
///
/// There should be no runtime impact in release builds, as the function is inlined and
/// has no executable code.
/// - Parameter value: The value for which you want to suppress "variable unused" warnings.
@_spi(Generated)
@inline(__always)
public func suppressUnusedWarning<T>(_ value: T) {}
Loading