Skip to content

Instantly share code, notes, and snippets.

@Hungs20
Created February 5, 2024 07:13
Show Gist options
  • Save Hungs20/aba4df28aa80b53c715542b3caaf8395 to your computer and use it in GitHub Desktop.
Save Hungs20/aba4df28aa80b53c715542b3caaf8395 to your computer and use it in GitHub Desktop.
Flexible codable
extension KeyedDecodingContainer {
enum FlexibleValue<T: Decodable>: Decodable {
case int(Int)
case string(String)
case double(Double)
case float(Float)
case bool(Bool)
case null
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self = .null
return
}
if let intValue = try? container.decode(Int.self) {
self = .int(intValue)
} else if let stringValue = try? container.decode(String.self) {
self = .string(stringValue)
} else if let doubleValue = try? container.decode(Double.self) {
self = .double(doubleValue)
} else if let boolValue = try? container.decode(Bool.self) {
self = .bool(boolValue)
} else {
throw DecodingError.typeMismatch(FlexibleValue.self, DecodingError.Context(codingPath: container.codingPath, debugDescription: "Unsupported flexible value type"))
}
}
}
func decodeFlexibleValue<T>(_ key: Key) throws -> T? where T: Decodable, T: LosslessStringConvertible {
do {
let flexibleValue = try self.decode(FlexibleValue<T>.self, forKey: key)
switch flexibleValue {
case .int(let intValue):
return T(String(intValue))
case .string(let stringValue):
return T(stringValue)
case .double(let doubleValue):
return T(String(doubleValue))
case .float(let floatValue):
return T(String(floatValue))
case .bool(let boolValue):
return T(String(boolValue))
case .null:
return nil
}
} catch {
return nil
}
}
func decodeFlexibleValue<T>(_ key: Key, defaultValue: T) throws -> T where T: Decodable, T: LosslessStringConvertible {
return try self.decodeFlexibleValue(key) ?? defaultValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment