{"id":27600664,"url":"https://github.com/reers/ReerCodable","last_synced_at":"2025-04-22T17:03:13.158Z","repository":{"id":258309105,"uuid":"872774490","full_name":"reers/ReerCodable","owner":"reers","description":"Codable extensions using Swift Macro","archived":false,"fork":false,"pushed_at":"2025-04-11T02:05:29.000Z","size":12257,"stargazers_count":138,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T03:20:10.621Z","etag":null,"topics":["ananda","bettercodable","codable","codablewrapper","codablewrappers","decode","encode","jsonparser","jsonserializer","jsontomodel","kakajson","metacodable","mjextension","objectmapper","reercodable","swiftmacro","yymodel"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reers.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-15T03:48:03.000Z","updated_at":"2025-04-11T02:05:32.000Z","dependencies_parsed_at":"2024-10-18T11:49:35.415Z","dependency_job_id":"626a7171-d5b6-4004-94dd-7f9415cb872c","html_url":"https://github.com/reers/ReerCodable","commit_stats":null,"previous_names":["reers/reercodable"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reers%2FReerCodable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reers%2FReerCodable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reers%2FReerCodable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reers%2FReerCodable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reers","download_url":"https://codeload.github.com/reers/ReerCodable/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250285644,"owners_count":21405296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ananda","bettercodable","codable","codablewrapper","codablewrappers","decode","encode","jsonparser","jsonserializer","jsontomodel","kakajson","metacodable","mjextension","objectmapper","reercodable","swiftmacro","yymodel"],"created_at":"2025-04-22T17:01:20.863Z","updated_at":"2025-04-22T17:03:13.141Z","avatar_url":"https://github.com/reers.png","language":"Swift","readme":"[简体中文](README_CN.md)\n\n# ReerCodable\nExtension of `Codable` using Swift macros to make serialization simpler with declarative annotations!\n\n```swift\n@Codable\n@SnakeCase\nstruct User {\n    @CodingKey(\"user_name\")\n    var name: String\n    \n    @KebabCase\n    @DateCoding(.iso8601)\n    var birthDate: Date\n    \n    @CodingKey(\"location.city\")\n    var city: String\n    \n    @CustomCoding\u003cDouble\u003e(\n        decode: { return try $0.value(forKeys: \"height_in_meters\") * 100.0 },\n        encode: { try $0.set($1 / 100.0, forKey: \"height_in_meters\") }\n    )\n    var height: Double\n}\n```\n\n# Overview\nReerCodable framework provides a series of custom macros for generating dynamic Codable implementations. The core of the framework is the @Codable() macro, which generates concrete implementations under data annotations provided by other macros (⚠️ Only the `@Codable` macro can be expanded in XCode macro expansion, expanding other macros will have no response)\n\nThe framework has been fully tested using [Swift Testing](https://developer.apple.com/xcode/swift-testing/). \n\nMain features include:\n- Declare custom `CodingKey` values for each property through `@CodingKey(\"key\")`, without writing all `CodingKey` values.\n- Support nested `CodingKey` through string expressions, like `@CodingKey(\"nested.key\")`\n- Allow using multiple `CodingKey`s for Decode, like `@CodingKey(\"key1\", \"key2\")`\n- Support using `@SnakeCase`, `KebabCase` etc. to mark types or properties for easy naming conversion\n- Customize nested containers during Coding using `@CodingContainer`\n- Support specified `CodingKey` for Encode, like `EncodingKey(\"encode_key\")`\n- Allow using default values when decoding fails to avoid `keyNotFound` errors\n- Allow using `@CodingIgnored` to ignore specific properties during encoding/decoding\n- Support automatic conversion between base64 strings and `Data` `[UInt8]` types using `@Base64Coding`\n- Through `@CompactDecoding`, ignore `null` values when Decoding `Array`, `Dictionary`, `Set` instead of throwing errors\n- Support various encoding/decoding of `Date` through `@DateCoding`\n- Support custom encoding/decoding logic through `@CustomCoding`\n- Better support for subclasses using `@InheritedCodable`\n- Provide simple and rich encoding/decoding capabilities for various `enum` types\n- Support encoding/decoding lifecycle through `ReerCodableDelegate`, like `didDecode`, `willEncode`\n- Provide extensions to support using JSON String, `Dictionary`, `Array` directly as parameters for encoding/decoding\n- Support conversion between basic data types like `Bool`, `String`, `Double`, `Int`, `CGFloat`\n- Support BigInt `Int128`, `UInt128` on macOS 15+, iOS 13+\n- Support encoding/decoding of `Any` through `AnyCodable`, like `var dict = [String: AnyCodable]`\n- Auto-generate default instances: \n  Use `@DefaultInstance` to automatically create a default instance of your type, \n  accessible through `Model.default`\n- Flexible copying with updates: \n  The `@Copyable` macro generates a powerful `copy()` method that allows both \n  full copies and selective property updates in a single call\n\n# Requirements\nXCode 16.0+\n\niOS 13.0+, macOS 10.15+, tvOS 13.0+, visionOS 1.0+, watchOS 6.0+\n\nSwift 5.10+\n\nswift-syntax 600.0.0+\n\n# Installation\n\u003cdetails\u003e\n\u003csummary\u003eSwift Package Manager\u003c/summary\u003e\n\u003c/br\u003e\n\u003cp\u003eYou can install ReerCodable using \u003ca href=\"https://swift.org/package-manager\"\u003eThe Swift Package Manager\u003c/a\u003e by adding the proper description to your \u003ccode\u003ePackage.swift\u003c/code\u003e file:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"swift language-swift\"\u003eimport PackageDescription\nlet package = Package(\n    name: \"YOUR_PROJECT_NAME\",\n    targets: [],\n    dependencies: [\n        .package(url: \"https://github.com/reers/ReerCodable.git\", from: \"1.1.7\")\n    ]\n)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThen, add ReerCodable to your targets dependencies like so:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"swift language-swift\"\u003e.product(name: \"ReerCodable\", package: \"ReerCodable\"),\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eFinally, run \u003ccode\u003eswift package update\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCocoaPods\u003c/summary\u003e\n\u003c/br\u003e\n\u003cp\u003eSince CocoaPods doesn't directly support Swift Macro, the macro implementation can be compiled into binary for use. The integration method is as follows, requiring \u003ccode\u003es.pod_target_xcconfig\u003c/code\u003e to load the binary plugin of macro implementation:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby language-ruby\"\u003e\nPod::Spec.new do |s|\n  s.name             = 'YourPod'\n  s.dependency 'ReerCodable', '1.1.7'\n  # Copy the following config to your pod\n  s.pod_target_xcconfig = {\n    'OTHER_SWIFT_FLAGS' =\u003e '-Xfrontend -load-plugin-executable -Xfrontend ${PODS_ROOT}/ReerCodable/Sources/Resources/ReerCodableMacros#ReerCodableMacros'\n  }\nend\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eAlternatively, if not using \u003ccode\u003es.pod_target_xcconfig\u003c/code\u003e and \u003ccode\u003es.user_target_xcconfig\u003c/code\u003e, you can add the following script in podfile for unified processing:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"ruby language-ruby\"\u003e\n    post_install do |installer|\n      installer.pods_project.targets.each do |target|\n        rhea_dependency = target.dependencies.find { |d| ['ReerCodable'].include?(d.name) }\n        if rhea_dependency\n          puts \"Adding ReerCodable Swift flags to target: #{target.name}\"\n          target.build_configurations.each do |config|\n            swift_flags = config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['$(inherited)']\n            plugin_flag = '-Xfrontend -load-plugin-executable -Xfrontend ${PODS_ROOT}/ReerCodable/Sources/Resources/ReerCodableMacros#ReerCodableMacros'\n            unless swift_flags.join(' ').include?(plugin_flag)\n              swift_flags.concat(plugin_flag.split)\n            end\n            config.build_settings['OTHER_SWIFT_FLAGS'] = swift_flags\n          end\n        end\n      end\n    end\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003c/details\u003e\n\n# Usage\n\nReerCodable greatly simplifies Swift's serialization process through declarative annotations. Here are detailed examples of each feature:\n\n### 1. Custom CodingKey\n\nUse `@CodingKey` to specify custom keys for properties without manually writing `CodingKeys` enum:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eReerCodable\u003c/th\u003e\n\u003cth\u003eCodable\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\n@Codable\nstruct User {\n    @CodingKey(\"user_name\")\n    var name: String\n    \n    @CodingKey(\"user_age\")\n    var age: Int\n    \n    var height: Double\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```swift\nstruct User: Codable {\n    var name: String\n    var age: Int\n    var height: Double\n    \n    enum CodingKeys: String, CodingKey {\n        case name = \"user_name\"\n        case age = \"user_age\"\n        case height\n    }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### 2. Nested CodingKey\n\nSupport nested key paths using dot notation:\n\n```swift\n@Codable\nstruct User {\n    @CodingKey(\"other_info.weight\")\n    var weight: Double\n    \n    @CodingKey(\"location.city\")\n    var city: String\n}\n```\n\n### 3. Multiple Keys for Decoding\n\nMultiple keys can be specified for decoding, the system will try decoding in order until successful:\n\n```swift\n@Codable\nstruct User {\n    @CodingKey(\"name\", \"username\", \"nick_name\")\n    var name: String\n}\n```\n\n### 4. Name Style Conversion\n\nSupport multiple naming style conversions, can be applied to types or individual properties:\n\n```swift\n@Codable\n@SnakeCase\nstruct Person {\n    var firstName: String  // decoded from \"first_name\" or encoded to \"first_name\"\n    \n    @KebabCase\n    var lastName: String   // decoded from \"last-name\" or encoded to \"last-name\"\n}\n```\n\n### 5. Custom Coding Container\n\nUse `@CodingContainer` to customize the container path for encoding and decoding, typically used when dealing with heavily nested JSON structures while wanting the model declaration to directly match a sub-level structure:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eReerCodable\u003c/th\u003e\n\u003cth\u003eJSON\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\n@Codable\n@CodingContainer(\"data.info\")\nstruct UserInfo {\n    var name: String\n    var age: Int\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```json\n{\n    \"code\": 0,\n    \"data\": {\n        \"info\": {\n            \"name\": \"phoenix\",\n            \"age\": 33\n        }\n    }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### 6. Encoding-Specific Key\n\nDifferent key names can be specified for the encoding process. Since `@CodingKey` may have multiple parameters, and can use `@SnakeCase`, `KebabCase`, etc., decoding may use multiple keys, then encoding will use the first key, or `@EncodingKey` can be used to specify the key\n\n```swift\n@Codable\nstruct User {\n    @CodingKey(\"user_name\")      // decoding uses \"user_name\", \"name\"\n    @EncodingKey(\"name\")         // encoding uses \"name\"\n    var name: String\n}\n```\n\n### 7. Default Value Support\n\nDefault values can be used when decoding fails. Native `Codable` throws an exception for non-`Optional` properties when the correct value is not parsed, even if an initial value has been set, or even if it's an `Optional` type enum\n\n```swift\n@Codable\nstruct User {\n    var age: Int = 33\n    var name: String = \"phoenix\"\n    // If the `gender` field in the JSON is neither `male` nor `female`, the native Codable will throw an exception, whereas ReerCodable will not and instead set it to nil. For example, with `{\"gender\": \"other\"}`, this scenario might occur when the client has defined an enum but the server has added new fields in a business context.\n    var gender: Gender?\n}\n\n@Codable\nenum Gender: String {\n    case male, female\n}\n```\n\n### 8. Ignore Properties\n\nUse `@CodingIgnored` to ignore specific properties during encoding/decoding. During decoding, non-`Optional` properties must have a default value to satisfy Swift initialization requirements. `ReerCodable` automatically generates default values for basic data types and collection types. For other custom types, users need to provide default values.\n\n```swift\n@Codable\nstruct User {\n    var name: String\n    \n    @CodingIgnored\n    var ignore: Set\u003cString\u003e\n}\n```\n\n### 9. Base64 Coding\n\nAutomatically handle conversion between base64 strings and `Data`, `[UInt8]` types:\n\n```swift\n@Codable\nstruct User {\n    @Base64Coding\n    var avatar: Data\n    \n    @Base64Coding\n    var voice: [UInt8]\n}\n```\n\n### 10. Collection Type Decoding Optimization\n\nUse `@CompactDecoding` to automatically filter null values when decoding arrays, same meaning as `compactMap`:\n\n```swift\n@Codable\nstruct User {\n    @CompactDecoding\n    var tags: [String]  // [\"a\", null, \"b\"] will be decoded as [\"a\", \"b\"]\n}\n```\nAt the same time, both `Dictionary` and `Set` also support the use of `@CompactDecoding` for optimization.\n\n### 11. Date Coding\n\nSupport various date format encoding/decoding:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eReerCodable\u003c/th\u003e\n\u003cth\u003eJSON\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\n@Codable\nclass DateModel {\n    @DateCoding(.timeIntervalSince2001)\n    var date1: Date\n    \n    @DateCoding(.timeIntervalSince1970)\n    var date2: Date\n    \n    @DateCoding(.secondsSince1970)\n    var date3: Date\n    \n    @DateCoding(.millisecondsSince1970)\n    var date4: Date\n    \n    @DateCoding(.iso8601)\n    var date5: Date\n    \n    @DateCoding(.formatted(Self.formatter))\n    var date6: Date\n    \n    static let formatter: DateFormatter = {\n        let dateFormatter = DateFormatter()\n        dateFormatter.locale = Locale(identifier: \"en_US_POSIX\")\n        dateFormatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ss.SSS\"\n        dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)\n        return dateFormatter\n    }()\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```json\n{\n    \"date1\": 1431585275,\n    \"date2\": 1731585275.944,\n    \"date3\": 1731585275,\n    \"date4\": 1731585275944,\n    \"date5\": \"2024-12-10T00:00:00Z\",\n    \"date6\": \"2024-12-10T00:00:00.000\"\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### 12. Custom Encoding/Decoding Logic\n\nImplement custom encoding/decoding logic through `@CustomCoding`. There are two ways to customize encoding/decoding:\n- Through closures, using `decoder: Decoder`, `encoder: Encoder` as parameters to implement custom logic:\n\n```swift\n@Codable\nstruct User {\n    @CustomCoding\u003cDouble\u003e(\n        decode: { return try $0.value(forKeys: \"height_in_meters\") * 100.0 },\n        encode: { try $0.set($1 / 100.0, forKey: \"height_in_meters\") }\n    )\n    var heightInCentimeters: Double\n}\n```\n- Through a custom type implementing the `CodingCustomizable` protocol to implement custom logic:\n```swift\n// 1st 2nd 3rd 4th 5th  -\u003e 1 2 3 4 5\nstruct RankTransformer: CodingCustomizable {\n    \n    typealias Value = UInt\n    \n    static func decode(by decoder: any Decoder, keys: [String]) throws -\u003e UInt {\n        var temp: String = try decoder.value(forKeys: keys)\n        temp.removeLast(2)\n        return UInt(temp) ?? 0\n    }\n    \n    static func encode(by encoder: Encoder, key: String, value: Value) throws {\n        try encoder.set(value, forKey: key)\n    }\n}\n\n@Codable\nstruct HundredMeterRace {\n    @CustomCoding(RankTransformer.self)\n    var rank: UInt\n}\n```\nDuring custom implementation, the framework provides methods that can make encoding/decoding more convenient:\n```swift\npublic extension Decoder {\n    func value\u003cValue: Decodable\u003e(forKeys keys: String...) throws -\u003e Value {\n        let container = try container(keyedBy: AnyCodingKey.self)\n        return try container.decode(type: Value.self, keys: keys)\n    }\n}\n\npublic extension Encoder {\n    func set\u003cValue: Encodable\u003e(_ value: Value, forKey key: String, treatDotAsNested: Bool = true) throws {\n        var container = container(keyedBy: AnyCodingKey.self)\n        try container.encode(value: value, key: key, treatDotAsNested: treatDotAsNested)\n    }\n}\n```\n\n### 13. Inheritance Support\n\nUse `@InheritedCodable` for better support of subclass encoding/decoding. Native `Codable` cannot parse subclass properties, even if the value exists in JSON, requiring manual implementation of `init(from decoder: Decoder) throws`\n\n```swift\n@Codable\nclass Animal {\n    var name: String\n}\n\n@InheritedCodable\nclass Cat: Animal {\n    var color: String\n}\n```\n\n### 14. Enum Support\n\nProvide rich encoding/decoding capabilities for enums:\n- Support for basic enum types and RawValue enums\n```swift\n@Codable\nstruct User {\n    let gender: Gender\n    let rawInt: RawInt\n    let rawDouble: RawDouble\n    let rawDouble2: RawDouble2\n    let rawString: RawString\n}\n\n@Codable\nenum Gender {\n    case male, female\n}\n\n@Codable\nenum RawInt: Int {\n    case one = 1, two, three, other = 100\n}\n\n@Codable\nenum RawDouble: Double {\n    case one, two, three, other = 100.0\n}\n\n@Codable\nenum RawDouble2: Double {\n    case one = 1.1, two = 2.2, three = 3.3, other = 4.4\n}\n\n@Codable\nenum RawString: String {\n    case one, two, three, other = \"helloworld\"\n}\n```\n- Support using `CodingCase(match: ....)` to match multiple values or ranges\n```swift\n@Codable\nenum Phone: Codable {\n    @CodingCase(match: .bool(true), .int(10), .string(\"iphone\"), .intRange(22...30))\n    case iPhone\n    \n    @CodingCase(match: .int(12), .string(\"MI\"), .string(\"xiaomi\"), .doubleRange(50...60))\n    case xiaomi\n    \n    @CodingCase(match: .bool(false), .string(\"oppo\"), .stringRange(\"o\"...\"q\"))\n    case oppo\n}\n```\n- For enums with associated values, support using `CaseValue` to match associated values, use `.label()` to declare matching logic for labeled associated values, use `.index()` to declare matching logic for unlabeled associated values. `ReerCodable` supports two JSON formats for enum matching\n    - The first is also supported by native `Codable`, where the enum value and its associated values have a parent-child structure:\n    ```swift\n    @Codable\n    enum Video: Codable {\n        /// {\n        ///     \"YOUTUBE\": {\n        ///         \"id\": \"ujOc3a7Hav0\",\n        ///         \"_1\": 44.5\n        ///     }\n        /// }\n        @CodingCase(match: .string(\"youtube\"), .string(\"YOUTUBE\"))\n        case youTube\n        \n        /// {\n        ///     \"vimeo\": {\n        ///         \"ID\": \"234961067\",\n        ///         \"minutes\": 999999\n        ///     }\n        /// }\n        @CodingCase(\n            match: .string(\"vimeo\"),\n            values: [.label(\"id\", keys: \"ID\", \"Id\"), .index(2, keys: \"minutes\")]\n        )\n        case vimeo(id: String, duration: TimeInterval = 33, Int)\n        \n        /// {\n        ///     \"tiktok\": {\n        ///         \"url\": \"https://example.com/video.mp4\",\n        ///         \"tag\": \"Art\"\n        ///     }\n        /// }\n        @CodingCase(\n            match: .string(\"tiktok\"),\n            values: [.label(\"url\", keys: \"url\")]\n        )\n        case tiktok(url: URL, tag: String?)\n    }\n    ```\n    - The second is where enum values and their associated values are at the same level or have custom matching structures, using `.pathValue()` for custom path value matching\n    ```swift\n    @Codable\n    enum Video1: Codable {\n        /// {\n        ///     \"type\": {\n        ///         \"middle\": \"youtube\"\n        ///     }\n        /// }\n        @CodingCase(match: .pathValue(\"type.middle.youtube\"))\n        case youTube\n        \n        /// {\n        ///     \"type\": \"vimeo\",\n        ///     \"ID\": \"234961067\",\n        ///     \"minutes\": 999999\n        /// }\n        @CodingCase(\n            match: .pathValue(\"type.vimeo\"),\n            values: [.label(\"id\", keys: \"ID\", \"Id\"), .index(2, keys: \"minutes\")]\n        )\n        case vimeo(id: String, duration: TimeInterval = 33, Int)\n        \n        /// {\n        ///     \"type\": \"tiktok\",\n        ///     \"media\": \"https://example.com/video.mp4\",\n        ///     \"tag\": \"Art\"\n        /// }\n        @CodingCase(\n            match: .pathValue(\"type.tiktok\"),\n            values: [.label(\"url\", keys: \"media\")]\n        )\n        case tiktok(url: URL, tag: String?)\n    }\n    ```\n\n### 15. Lifecycle Callbacks\n\nSupport encoding/decoding lifecycle callbacks:\n\n```swift\n@Codable\nclass User {\n    var age: Int\n    \n    func didDecode(from decoder: any Decoder) throws {\n        if age \u003c 0 {\n            throw ReerCodableError(text: \"Invalid age\")\n        }\n    }\n    \n    func willEncode(to encoder: any Encoder) throws {\n        // Process before encoding\n    }\n}\n\n@Codable\nstruct Child: Equatable {\n    var name: String\n    \n    mutating func didDecode(from decoder: any Decoder) throws {\n        name = \"reer\"\n    }\n    \n    func willEncode(to encoder: any Encoder) throws {\n        print(name)\n    }\n}\n\n```\n\n### 16. JSON Extension Support\n\nProvide convenient JSON string and dictionary conversion methods:\n\n```swift\nlet jsonString = \"{\\\"name\\\": \\\"Tom\\\"}\"\nlet user = try User.decode(from: jsonString)\n\nlet dict: [String: Any] = [\"name\": \"Tom\"]\nlet user2 = try User.decode(from: dict)\n```\n\n### 17. Basic Type Conversion\n\nSupport automatic conversion between basic data types:\n\n```swift\n@Codable\nstruct User {\n    @CodingKey(\"is_vip\")\n    var isVIP: Bool    // \"1\" or 1 can be decoded as true\n    \n    @CodingKey(\"score\")\n    var score: Double  // \"100\" or 100 can be decoded as 100.0\n}\n```\n\n### 18. AnyCodable Support\n\nImplement encoding/decoding of `Any` type through `AnyCodable`:\n\n```swift\n@Codable\nstruct Response {\n    var data: AnyCodable  // Can store data of any type\n    var metadata: [String: AnyCodable]  // Equivalent to [String: Any] type\n}\n```\n\n### 19. Generate Default Instance\n\n```swift\n@Codable\n@DefaultInstance\nstruct ImageModel {\n    var url: URL\n}\n\n@Codable\n@DefaultInstance\nstruct User5 {\n    let name: String\n    var age: Int = 22\n    var uInt: UInt = 3\n    var data: Data\n    var date: Date\n    var decimal: Decimal = 8\n    var uuid: UUID\n    var avatar: ImageModel\n    var optional: String? = \"123\"\n    var optional2: String?\n}\n```\n\nWill generate the following instance:\n\n```swift\nstatic let `default` = User5(\n    name: \"\",\n    age: 22,\n    uInt: 3,\n    data: Data(),\n    date: Date(),\n    decimal: 8,\n    uuid: UUID(),\n    avatar: ImageModel.default,\n    optional: \"123\",\n    optional2: nil\n)\n```\n\n⚠️ Note: Properties with generic types are NOT supported with `@DefaultInstance`\n```swift\n@Codable\nstruct NetResponse\u003cElement: Codable\u003e {\n    let data: Element?\n    let msg: String\n    private(set) var code: Int = 0\n}\n```\n\n### 20. Generate Copy Method\nUse `Copyable` to generate `copy` method for models\n\n```swift\n@Codable\n@Copyable\npublic struct Model6 {\n    var name: String\n    let id: Int\n    var desc: String?\n}\n\n@Codable\n@Copyable\nclass Model7\u003cElement: Codable\u003e {\n    var name: String\n    let id: Int\n    var desc: String?\n    var data: Element?\n}\n```\n\nGenerates the following `copy` methods. As you can see, besides default copy, you can also update specific properties:\n\n```swift\npublic func copy(\n    name: String? = nil,\n    id: Int? = nil,\n    desc: String? = nil\n) -\u003e Model6 {\n    return .init(\n        name: name ?? self.name,\n        id: id ?? self.id,\n        desc: desc ?? self.desc\n    )\n}\n\nfunc copy(\n    name: String? = nil,\n    id: Int? = nil,\n    desc: String? = nil,\n    data: Element? = nil\n) -\u003e Model7 {\n    return .init(\n        name: name ?? self.name,\n        id: id ?? self.id,\n        desc: desc ?? self.desc,\n        data: data ?? self.data\n    )\n}\n```\n\nThese examples demonstrate the main features of ReerCodable, which can help developers greatly simplify the encoding/decoding process, improving code readability and maintainability.\n","funding_links":[],"categories":["Libs","Swift"],"sub_categories":["Data Management"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freers%2FReerCodable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freers%2FReerCodable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freers%2FReerCodable/lists"}