Swift-codable-macro: macros for custom conformance to Codable

Previously in this post, I proposed a few macros to include custom coding path when conforming to Codable and have created a initial implementation. Now more features are added to the packages.

Now besides customizing coding path with @CodingField and ignoring fields with CodingIgnore, the following features are now supported:

  • Transform the value before encoding and after decoding with @CodingTransform, @DecodeTransform and @EncodeTransform
  • Validate the decoded value with @CodingValidate
  • Provide settings for decoding sequence type with @SequenceCodin ![Screenshot 2025-06-14 at 05.00.20|690x53](upload://gFRJvfirFf3kecAlg4zaP8krNsC.png) gField
  • Encode the whole instance by converting it into some single Codable value with @SingleValueCodable
  • Encode Enums with @EnumCodable.

For more information, please refer to the documentation

Examples:

@Codable
struct Person {

    @CodingField("data", "id")
    @DecodeTransform(source: String.self, with: { UUID(uuidString: $0)! })
    @EncodeTransform(source: UUID.self, with: \.uuidString)
    var id: UUID

    @CodingField("data", "meta", "name")
    @CodingValidate(source: String.self, with: { !$0.isEmpty })
    @CodingValidate(source: String.self, with: { !$0.contains(where: { $0.isNumber }) })
    var name: String 

    @CodingTransform(
        .date.timeIntervalTransform(),  // Date to TimeInterval (Double)
        .double.multiRepresentationTransform(encodeTo: .string)   // Double to String
    )    
    var birthday: Date

    @CodingIgnore
    var habit: String = "writing Swift Macro"

    @CodingField("data", "meta", "known_programming_languages")
    @SequenceCodingField(
        subPath: "name", 
        onMissing: .ignore, 
        onMismatch: .value("Swift"),
        decodeTransform: Set.init
    )
    var knownProgrammingLanguages: Set<String>

}
@SingleValueCodable
struct FilePath {
    @SingleValueCodableDelegate
    var storage: String
    var isDir: Bool = false 
}
@EnumCodable(option: .adjacentKeyed())
enum Example {
    @EnumCaseCoding(caseKey: "a_key", emptyPayloadOption: .emptyObject)
    case a
    @EnumCaseCoding(caseKey: "a_key", payload: .singleValue)
    case b(Int)
    @EnumCaseCoding(payload: .object(keys: "key1", "key2", "key3"))
    case c(Int, label: String, _: Int)
}

And as before, the macros provide diagnostics in compile time for some errors.






5 Likes