//===----------------------------------------------------------------------===// // Copyright © 2025-2026 Apple Inc. and the Containerization project authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //===----------------------------------------------------------------------===// import Foundation /// The core error type for Containerization. /// /// Most API surfaces for the core container/process/agent types will /// return a ContainerizationError. public struct ContainerizationError: Swift.Error, Sendable { /// A code describing the error encountered. public var code: Code /// A description of the error. public var message: String /// The original error which led to this error being thrown. public var cause: (any Error)? /// Creates a new error. /// /// - Parameters: /// - code: The error code. /// - message: A description of the error. /// - cause: The original error which led to this error being thrown. public init(_ code: Code, message: String, cause: (any Error)? = nil) { self.code = code self.message = message self.cause = cause } /// Creates a new error. /// /// - Parameters: /// - rawCode: The error code value as a String. /// - message: A description of the error. /// - cause: The original error which led to this error being thrown. public init(_ rawCode: String, message: String, cause: (any Error)? = nil) { self.code = Code(rawValue: rawCode) self.message = message self.cause = cause } /// Provides a unique hash of the error. public func hash(into hasher: inout Hasher) { hasher.combine(self.code) hasher.combine(self.message) } /// Equality operator for the error. Uses the code and message. public static func == (lhs: Self, rhs: Self) -> Bool { lhs.code == rhs.code && lhs.message == rhs.message } /// Checks if the given error has the provided code. public func isCode(_ code: Code) -> Bool { self.code == code } } extension ContainerizationError: CustomStringConvertible { /// Description of the error. public var description: String { guard let cause = self.cause else { return "\(self.code): \"\(self.message)\"" } return "\(self.code): \"\(self.message)\" (cause: \"\(cause)\")" } } extension ContainerizationError: LocalizedError { /// A localized message describing what error occurred. public var errorDescription: String? { guard let cause = self.cause else { return message } return "\(message) (cause: \"\(cause)\")" } } extension ContainerizationError { /// Codes for a `ContainerizationError`. public struct Code: Sendable, Hashable { private enum Value: Hashable, Sendable, CaseIterable { case unknown case invalidArgument case internalError case exists case notFound case cancelled case invalidState case empty case timeout case unsupported case interrupted } private var value: Value private init(_ value: Value) { self.value = value } init(rawValue: String) { let values = Value.allCases.reduce(into: [String: Value]()) { $0[String(describing: $1)] = $1 } let match = values[rawValue] guard let match else { fatalError("invalid code value \(rawValue)") } self.value = match } public static var unknown: Self { Self(.unknown) } public static var invalidArgument: Self { Self(.invalidArgument) } public static var internalError: Self { Self(.internalError) } public static var exists: Self { Self(.exists) } public static var notFound: Self { Self(.notFound) } public static var cancelled: Self { Self(.cancelled) } public static var invalidState: Self { Self(.invalidState) } public static var empty: Self { Self(.empty) } public static var timeout: Self { Self(.timeout) } public static var unsupported: Self { Self(.unsupported) } public static var interrupted: Self { Self(.interrupted) } } } extension ContainerizationError.Code: CustomStringConvertible { public var description: String { String(describing: self.value) } }