Skip to content

Instantly share code, notes, and snippets.

@EricRabil
Last active August 19, 2021 14:43
Show Gist options
  • Select an option

  • Save EricRabil/b03ff3abbc1a745fa9e809bc1878f609 to your computer and use it in GitHub Desktop.

Select an option

Save EricRabil/b03ff3abbc1a745fa9e809bc1878f609 to your computer and use it in GitHub Desktop.
Write anonymous encoding and decoding functions that can convert any arbitrary values back and forth
import Foundation
// somewhere in a different module
struct MyArbitraryUncodableStruct {
let aBool: Bool
let aInt: Int
}
extension JSONEncoder {
private class CustomEncodable: Encodable {
private let encode: (Encoder) throws -> ()
init(_ encode: @escaping (Encoder) throws -> ()) {
self.encode = encode
}
func encode(to encoder: Encoder) throws {
try encode(encoder)
}
}
func encode(_ cb: @escaping (Encoder) throws -> ()) throws -> Data {
try encode(CustomEncodable(cb))
}
}
extension JSONDecoder {
private class CustomDecodable: Decodable {
static var decoder: ((Decoder) throws -> Any)!
let decodedValue: Any
required init(from decoder: Decoder) throws {
decodedValue = try Self.decoder(decoder)
}
}
func decode<P>(data: Data, _ cb: @escaping (Decoder) throws -> P) throws -> P {
// this would be better but we cant have anonymous classes yet so fuck you and also JSONParser is marked internal so fuck you
// https://github.com/apple/swift-corelibs-foundation/blob/main/Sources/Foundation/JSONSerialization%2BParser.swift
CustomDecodable.decoder = cb
defer { CustomDecodable.decoder = nil }
return try decode(CustomDecodable.self, from: data).decodedValue as! P
}
}
// your code
let instance = MyArbitraryUncodableStruct(aBool: true, aInt: 54)
extension MyArbitraryUncodableStruct {
enum CodingKeys: CodingKey {
case aBool, aInt
}
}
let data = try JSONEncoder().encode { encoder in
var container = encoder.container(keyedBy: MyArbitraryUncodableStruct.CodingKeys.self)
try container.encode(instance.aBool, forKey: .aBool)
try container.encode(instance.aInt, forKey: .aInt)
}
let parsed = try JSONDecoder().decode(data: data) { decoder -> MyArbitraryUncodableStruct in
let container = try decoder.container(keyedBy: MyArbitraryUncodableStruct.CodingKeys.self)
return MyArbitraryUncodableStruct(
aBool: try container.decode(Bool.self, forKey: .aBool),
aInt: try container.decode(Int.self, forKey: .aInt)
)
}
print(data)
print(String(decoding: data, as: UTF8.self))
print(parsed.aBool)
print(parsed.aInt)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment