Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import Foundation
protocol TransformerType {
associatedtype BaseType
associatedtype TypeForCoding: Codable
static var encodeTransform: (BaseType) throws -> TypeForCoding { get }
static var decodeTransform: (TypeForCoding) throws -> BaseType { get }
}
@propertyWrapper
struct CustomCodable<Transformer: TransformerType> {
var wrappedValue: Transformer.BaseType
}
extension CustomCodable: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let encoded = try container.decode(Transformer.TypeForCoding.self)
self.wrappedValue = try Transformer.decodeTransform(encoded)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let encoded = try Transformer.encodeTransform(self.wrappedValue)
try container.encode(encoded)
}
}
// Declare a custom transform
enum IntAsPoundString: TransformerType {
static let encodeTransform = { (base: Int) throws -> String in "#\(base)#" }
static let decodeTransform = { (encoded: String) throws -> Int in Int(encoded.replacingOccurrences(of: "#", with: "")) ?? 0 }
}
struct Article: Codable {
@CustomCodable<IntAsPoundString>
var id: Int
var name: String
}
// Demo
let art1 = Article(id: 42, name: "H2G2")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let j1 = String(data: try encoder.encode(art1), encoding: .utf8) ?? "<nil>"
print(j1)
/*
{
"id" : "#42#",
"name" : "H2G2"
}
*/
let art1decoded = try JSONDecoder().decode(Article.self, from: j1.data(using: .utf8)!)
print(art1decoded.id, art1decoded.name)
/* 42 H2G2 */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment