Last active
June 10, 2022 09:12
-
-
Save Dev1an/dfae2fb2d006898c0beab6dcc63a6c51 to your computer and use it in GitHub Desktop.
This is a workaround for the "Protocol 'Encodable' as a type cannot conform to the protocol itself" paradox. It provides a way to explicitly open up existential Encodable types and encode them using an encoder.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
let someEncodableThing: Encodable = "Hello world" | |
#if swift(>=5.7) | |
let data = try JSONEncoder().encode(json) | |
#else | |
let data = try JSONEncoder().encode(existential: json) | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Encode Existentials.swift | |
// | |
// This is a workaround for the "Protocol 'Encodable' as a type cannot conform to the protocol itself" paradox. | |
// All the code in this file can be safely removed after upgrading to the swift 5.7 compiler. | |
// Calls to ``TopLevelEncoder/encode(existential: Encodable)`` can then safely be replaced | |
// with a call to the encoder's `encode(_:)` function | |
// due to the "Implicitly Opened Existentials" (SE-0352) feature implemented in swift 5.7: https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md | |
// | |
// Created by Damiaan Dufaux on 09/06/2022. | |
// | |
#if swift(<5.7) | |
import class Foundation.JSONEncoder | |
extension JSONEncoder: TopLevelEncoder {} | |
/// A type that defines methods for encoding. | |
protocol TopLevelEncoder { | |
/// The type this encoder produces. | |
associatedtype Output | |
/// Encodes an instance of the indicated type. | |
/// | |
/// - Parameter value: The instance to encode. | |
func encode<T>(_ value: T) throws -> Self.Output where T : Encodable | |
} | |
extension TopLevelEncoder { | |
/// Explicitly opens an existential `Encodable` type and encodes it. | |
func encode(existential: Encodable) throws -> Output { | |
try existential.encode(using: self) | |
} | |
} | |
extension Encodable { | |
/// Explicitly opens a potential existential Encodable and encodes it using the specified TopLevelEncoder. | |
func encode<E: TopLevelEncoder>(using encoder: E) throws -> E.Output { | |
// `self` here, is a reference to the concrete 'underlying' type of a potential existential type. | |
try encoder.encode(self) | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment