[Shared] Adds @UserInfoValue property wrapper for ALTLocalizedErrors

ALTLocalizedErrors now automatically include all properties annotated with @UserInfoValue in userInfo when bridged to NSError.
This commit is contained in:
Riley Testut
2023-05-11 14:29:45 -05:00
committed by Magesh K
parent ea506b904d
commit 5b275d6811
3 changed files with 63 additions and 2 deletions

View File

@@ -69,13 +69,15 @@ public extension ALTLocalizedError
}
var errorUserInfo: [String : Any] {
let userInfo: [String: Any?] = [
var userInfo: [String: Any?] = [
NSLocalizedFailureErrorKey: self.errorFailure,
ALTLocalizedTitleErrorKey: self.errorTitle,
// ALTSourceFileErrorKey: self.sourceFile, // TODO: Figure out where these come from
// ALTSourceLineErrorKey: self.sourceLine,
]
userInfo.merge(self.userInfoValues) { (_, new) in new }
return userInfo.compactMapValues { $0 }
}
@@ -125,6 +127,21 @@ public extension ALTLocalizedError
}
}
private extension ALTLocalizedError
{
var userInfoValues: [(String, Any)] {
let userInfoValues = Mirror(reflecting: self).children.compactMap { (label, value) -> (String, Any)? in
guard let userInfoValue = value as? any UserInfoValueProtocol,
let key: any StringProtocol = userInfoValue.key ?? label?.dropFirst() // Remove leading underscore
else { return nil }
return (String(key), userInfoValue.wrappedValue)
}
return userInfoValues
}
}
public struct DefaultLocalizedError<Code: ALTErrorEnum>: ALTLocalizedError
{
public let code: Code

View File

@@ -0,0 +1,38 @@
//
// UserInfoValue.swift
// AltStore
//
// Created by Riley Testut on 5/2/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
protocol UserInfoValueProtocol<Value>
{
associatedtype Value
var key: String? { get }
var wrappedValue: Value { get }
}
@propertyWrapper
public struct UserInfoValue<Value>: UserInfoValueProtocol
{
public let key: String?
public var wrappedValue: Value
// Necessary for memberwise initializers to work as expected
// https://github.com/apple/swift-evolution/blob/main/proposals/0258-property-wrappers.md#memberwise-initializers
public init(wrappedValue: Value)
{
self.wrappedValue = wrappedValue
self.key = nil
}
public init(wrappedValue: Value, key: String)
{
self.wrappedValue = wrappedValue
self.key = key
}
}