All Projects → yonaskolb → Codability

yonaskolb / Codability

Licence: mit
Useful helpers for working with Codable types in Swift

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Codability

Jsonlab
JSONLab: a native JSON/UBJSON/MassagePack encoder/decoder for MATLAB/Octave
Stars: ✭ 202 (+61.6%)
Mutual labels:  json, encoding, decoding
Encoding
Go package containing implementations of efficient encoding, decoding, and validation APIs.
Stars: ✭ 705 (+464%)
Mutual labels:  json, encoding, decoding
Elixir Json
Native JSON library for Elixir
Stars: ✭ 216 (+72.8%)
Mutual labels:  json, encoding, decoding
Anycodable
Type-erased wrappers for Encodable, Decodable, and Codable values
Stars: ✭ 811 (+548.8%)
Mutual labels:  encoding, decoding, codable
Serpent
A protocol to serialize Swift structs and classes for encoding and decoding.
Stars: ✭ 281 (+124.8%)
Mutual labels:  json, encoding, decoding
Wrap
The easy to use Swift JSON encoder
Stars: ✭ 725 (+480%)
Mutual labels:  json, encoding
Himotoki
A type-safe JSON decoding library purely written in Swift
Stars: ✭ 786 (+528.8%)
Mutual labels:  json, decoding
Stegify
🔍 Go tool for LSB steganography, capable of hiding any file within an image.
Stars: ✭ 927 (+641.6%)
Mutual labels:  encoding, decoding
Jsontocodable
A generating tool from Raw JSON to Codable (Swift4) text written in Swift4.
Stars: ✭ 33 (-73.6%)
Mutual labels:  json, codable
Pbf
A low-level, lightweight protocol buffers implementation in JavaScript.
Stars: ✭ 618 (+394.4%)
Mutual labels:  encoding, decoding
X509
A PHP library for X.509 public key certificates, attribute certificates, certification requests and certification path validation.
Stars: ✭ 27 (-78.4%)
Mutual labels:  encoding, decoding
Fast ber
A C++11 ASN.1 BER Encoding and Decoding Library
Stars: ✭ 54 (-56.8%)
Mutual labels:  encoding, decoding
Scodec
Scala combinator library for working with binary data
Stars: ✭ 709 (+467.2%)
Mutual labels:  encoding, decoding
Bitmatch
A Rust crate that allows you to match, bind, and pack the individual bits of integers.
Stars: ✭ 82 (-34.4%)
Mutual labels:  encoding, decoding
Decodify
Detect and decode encoded strings, recursively.
Stars: ✭ 670 (+436%)
Mutual labels:  encoding, decoding
Rust Multibase
Multibase in rust
Stars: ✭ 30 (-76%)
Mutual labels:  encoding, decoding
Ldpc
C and MATLAB implementation for LDPC encoding and decoding
Stars: ✭ 76 (-39.2%)
Mutual labels:  encoding, decoding
Binary
Generic and fast binary serializer for Go
Stars: ✭ 86 (-31.2%)
Mutual labels:  encoding, decoding
Libbrotli
meta project to build libraries from the brotli source code
Stars: ✭ 110 (-12%)
Mutual labels:  encoding, decoding
Hashids.net
A small .NET package to generate YouTube-like hashes from one or many numbers. Use hashids when you do not want to expose your database ids to the user.
Stars: ✭ 470 (+276%)
Mutual labels:  encoding, decoding

Codability

SPM Git Version Build Status license

Useful helpers for working with Codable types in Swift

Installing

Swift Package Manager

Add the following to your Package.swift dependencies:

.package(url: "https://github.com/yonaskolb/Codability.git", from: "0.2.0"),

And then import wherever needed: import Codability

Helpers

Invalid Element Strategy

By default Decodable will throw an error if a single element within an array or dictionary fails. InvalidElementStrategy is an enum that lets you control this behaviour. It has multiple cases:

  • remove: Removes the element from the collection
  • fail: Will fail the whole decoding. This is the default behaviour used by the decoders
  • fallback(value): This lets you provide a typed value in a type safe way
  • custom((EncodingError)-> InvalidElementStrategy): Lets you provide dynamic behaviour depending on the specific error that was throw which lets you lookup exactly which keys were involved

When decoding an array or dictionary use the decodeArray and decodeDictionary functions (there are also IfPresent variants as well).

The InvalidElementStrategy can either be passed into these functions, or a default can be set using JSONDecoder().userInfo[.invalidElementStrategy], otherwise the default of fail will be used.

Given the following JSON:

{
    "array": [1, "two", 3],
    "dictionary": {
        "one": 1,
        "two": "two",
        "three": 3
    }
}
struct Object: Decodable {

    let array: [Int]
    let dictionary: [String: Int]

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RawCodingKey.self)
        array = try container.decodeArray([Int].self, forKey: "array", invalidElementStrategy: .fallback(0))
        dictionary = try container.decodeDictionary([String: Int].self, forKey: "dictionary", invalidElementStrategy: .remove)
    }
}
let decoder = JSONDecoder()

// this will provide a default if none is passed into the decode functions
decoder.userInfo[.invalidElementStrategy] = InvalidElementStrategy<Any>.remove

let decodedObject = try decoder.decode(Object.self, from: json)
decodedObject.array == [1,0,3]
decodedObject.dictionary = ["one": 1, "three": 3]

Any Codable

The downside of using Codable is that you can't encode and decode properties where the type is mixed or unknown, for example [String: Any], [Any] or Any. These are sometimes a neccessary evil in many apis, and AnyCodable makes supporting these types easy.

There are 2 few different way to use it:

As a Codable property

The advantage of this is you can use the synthesized codable functions. The downside though is that these values must be unwrapped using AnyCodable.value. You can add custom setters and getters on your objects to make accessing these easier though

struct AnyContainer: Codable {
    let dictionary: [String: AnyCodable]
    let array: [AnyCodable]
    let value: AnyCodable
}

Custom decoding and encoding functions

This lets you keep your normal structures, but requires using the decodeAny or encodeAny functions. If you have to implement a custom init(from:) or encode function for other reasons, this is the way to go. Behind the scenes this uses AnyCodable to do the coding, and then does a cast to your expect type in the case of decoding.

struct AnyContainer: Codable {
    let dictionary: [String: Any]
    let array: [Any]
    let value: Any
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        dictionary = try container.decodeAny(.dictionary)
        array = try container.decodeAny([Any].self, forKey: .array)
        value = try container.decodeAny(Any.self, forKey: .value)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeAny(dictionary, forKey: .dictionary)
        try container.encodeAny(array, forKey: .array)
        try container.encodeAny(value, forKey: .value)
    }
    
    enum CodingKeys: CodingKey {
        case dictionary
        case value
        case array
    }
}

Raw CodingKey

RawCodingKey can be used to provide dynamic coding keys. It also remove the need to create the standard CodingKey enum when you are only using those values in once place.

struct Object: Decodable {

    let int: Int
    let bool: Bool

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RawCodingKey.self)
        int = try container.decode(Int.self, forKey: "int")
        bool = try container.decode(Bool.self, forKey: "bool")
    }
}

Generic Decoding functions

The default decoding functions on KeyedDecodingContainer and UnkeyedDecodingContainer all require an explicity type to be passed in. Codabilty adds generic functions to remove the need for this, making your init(from:) much cleaner. The key parameter also becomes unnamed.

All the helper functions provided by Codabality such as the decodeAny, decodeArray or decodeDictionary functions also have these generic variants including IfPresent.

struct Object: Decodable {

    let int: Int?
    let bool: Bool

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RawCodingKey.self)
        
        // old
        int = try container.decodeIfPresent(Int.self, forKey: "int")
        bool = try container.decode(Bool.self, forKey: "bool")
        
        // new
        int = try container.decodeIfPresent("int")
        bool = try container.decode("bool")
    }
}

Other Codability helpers

JohnSundell/Codextended

Attributions

Thanks to @mattt and Flight-School/AnyCodable for the basis of AnyCodable support. License

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].