All Projects → GottaGetSwifty → Codablewrappers

GottaGetSwifty / Codablewrappers

Licence: apache-2.0
A Collection of PropertyWrappers to make custom Serialization of Swift Codable Types easy

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Codablewrappers

WXKDarkSky
A pure-Swift Codable layer over the Dark Sky API.
Stars: ✭ 21 (-89.34%)
Mutual labels:  swift-package-manager, codable
Bettercodable
Better Codable through Property Wrappers
Stars: ✭ 953 (+383.76%)
Mutual labels:  codable, swift-package-manager
Swiftprovisioningprofile
Parse iOS mobile provisioning files into Swift models
Stars: ✭ 55 (-72.08%)
Mutual labels:  codable, swift-package-manager
Licenseplist
A license list generator of all your dependencies for iOS applications
Stars: ✭ 1,996 (+913.2%)
Mutual labels:  swift-package-manager
Clendar
Clendar - universal calendar app. Written in SwiftUI. Available on App Store
Stars: ✭ 153 (-22.34%)
Mutual labels:  swift-package-manager
Carekit
CareKit is an open source software framework for creating apps that help people better understand and manage their health.
Stars: ✭ 2,142 (+987.31%)
Mutual labels:  swift-package-manager
Gitbuddy
Your buddy in managing and maintaining GitHub repositories, and releases. Automatically generate changelogs from issues and merged pull-requests.
Stars: ✭ 184 (-6.6%)
Mutual labels:  swift-package-manager
Cloudcore
Framework that enables syncing between iCloud (CloudKit) and Core Data
Stars: ✭ 146 (-25.89%)
Mutual labels:  swift-package-manager
Carting
🚘 A simple tool for updating Carthage script phase
Stars: ✭ 182 (-7.61%)
Mutual labels:  swift-package-manager
Multipeer
📱📲 A wrapper for the MultipeerConnectivity framework for automatic offline data transmission between devices
Stars: ✭ 170 (-13.71%)
Mutual labels:  swift-package-manager
Regularexpressiondecoder
A decoder that constructs objects from regular expression matches.
Stars: ✭ 169 (-14.21%)
Mutual labels:  codable
Kvkcalendar
A most fully customization calendar and timeline library for iOS 📅
Stars: ✭ 160 (-18.78%)
Mutual labels:  swift-package-manager
Cleanjson
Swift JSON decoder for Codable
Stars: ✭ 178 (-9.64%)
Mutual labels:  codable
Cdmarkdownkit
An extensive Swift framework providing simple and customizable markdown parsing.
Stars: ✭ 158 (-19.8%)
Mutual labels:  swift-package-manager
Swiftdb
A modern database abstraction layer, batteries included.
Stars: ✭ 183 (-7.11%)
Mutual labels:  codable
Ladybug
A powerful model framework for Swift 4
Stars: ✭ 147 (-25.38%)
Mutual labels:  codable
Swift Docker
Build & test your swift packages using docker - `swift docker test`
Stars: ✭ 179 (-9.14%)
Mutual labels:  swift-package-manager
Simplycoreaudio
A Swift framework that aims to make Core Audio use less tedious in macOS
Stars: ✭ 167 (-15.23%)
Mutual labels:  swift-package-manager
Messagepack
A MessagePack encoder and decoder for Codable types
Stars: ✭ 167 (-15.23%)
Mutual labels:  codable
Langserver Swift
A Swift implementation of the open Language Server Protocol.
Stars: ✭ 171 (-13.2%)
Mutual labels:  swift-package-manager

CodableWrappers

Swift Package Manager Platforms Build Status

Simplified Serialization with Property Wrappers

Move your Codable and (En/De)coder customization to annotations!

struct YourType: Codable {
    @MillisecondsSince1970DateCoding
    var millisecondsDate: Date
    @Base64Coding
    var someData: Data
    @OmitCoding
    var temporaryProperty
}

2.0's released! Release Notes


Installation

Swift Package Manager *Preferred*

URL:

https://github.com/GottaGetSwifty/CodableWrappers.git

Manifest:

dependencies: [
    .package(url: "https://github.com/GottaGetSwifty/CodableWrappers.git", .upToNextMajor(from: "2.0.0" )),
]

CocoaPods

pod 'CodableWrappers', '~> 2.0.0'

Info

Available Property Wrappers

Other Customization

Additional Links


Advantages

  • Declarative
  • Extendable
  • Declare once for all Encoders and Decoders. (e.g. JSONEncoder and PropertyListEncoder)
  • Custom (de/en)coding without overriding encode(to: Encoder) or init(with decoder) for your whole Type
  • Varied (de/en)coding strategies allowed
  • Cross Platform

Compatibility

2.x has a Swift 5.2 as it's minimum. 5.1 is available on 1.x


@EncodeNulls

For a Property that should encode null for nil values

struct MyType: Codable {
    @EncodeNulls
    var myText: String? // Will not be omitted when nil, e.g. will encode to `null` in JSON and `$null` in PLISTs
}

Lossy Collections

@LossyArrayDecoding
@LossyDictionaryDecoding
@LossySetDecoding

Filters null values during decoding without throwing an Error

private struct LossyCollectionModel: Codable, Equatable {
    @LossyArrayDecoding
    var array: [String] // Ignores null values without throwing an Error
    @LossyDictionaryDecoding
    var dictionary: [String:String] // Ignores null values without throwing an Error
    @LossySetDecoding
    var set: Set<String> // Ignores null values without throwing an Error
}

Empty Defaults

When you want to encode/decode an empty value rather than decoding nil or omitting encoding

struct MyType: Codable {
    @FallbackEncoding<EmptyInt>
    var int: Int? // will encode `0` when nil
    @FallbackDecoding<EmptyString>
    var string: String // will decode to "" when value was missing/nil
    @FallbackCoding<EmptyArray>
    var array: [Int]? // will encode/decode to [] when missing/nil
}
All Empty Values
EmptyBool
EmptyString
EmptyInt
EmptyInt16
EmptyInt32
EmptyInt64
EmptyInt8
EmptyUInt
EmptyUInt16
EmptyUInt32
EmptyUInt64
EmptyUInt8
EmptyCGFloat
EmptyDouble
EmptyFloat
EmptyFloat16
EmptyArray
EmptyDictionary
EmptySet

Empty defaults are available for most typical Foundation Types

Other Fallbacks

Any other kind of default can be provided by a custom FallbackValueProvider

public struct DistantFutureDateProvider: FallbackValueProvider {
    public static var defaultValue: Date { Date.distantFuture }
}

struct MyType: Codable {
    @FallbackEncoding<DistantFutureDateProvider>
    var updatedDate: Date?
}

@OmitCoding

For a Property you want to be ignore when (en/de)coding

struct MyType: Codable {
    @OmitCoding
    var myText: String? // Never encodes and ignores a value if one is in decoded data.
}

@Base64Coding

For a Data property that should be serialized to a Base64 encoded String

struct MyType: Codable {
    @Base64Coding
    var myData: Data // Now encodes to a Base64 String
}

@SecondsSince1970DateCoding

For a Date property that should be serialized to SecondsSince1970

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var myDate: Date // Now encodes to SecondsSince1970
}

@MillisecondsSince1970DateCoding

For a Date property that should be serialized to MillisecondsSince1970

struct MyType: Codable {
    @MillisecondsSince1970DateCoding
    var myDate: Date // Now encodes to MillisecondsSince1970
}

@DateFormatterCoding<DateFormatterStaticCoder>

For other Date formats create a Type that adheres to the DateFormatterStaticCoder Protocol and use the convenience @DateFormatterCoding typealias or @CodingUses<StaticCoder>.

struct MyCustomDateCoder: DateFormatterStaticCoder {
    static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "MM:dd:yy H:mm:ss"
        return formatter
    }()
}

struct MyType: Codable {
    @DateFormatterCoding<MyCustomDateCoder>
    var myDate: Date // Now encodes to the format: "MM:dd:yy H:mm:ss"
}

@ISO8601DateCoding

For a Date property that should be serialized using the ISO8601DateFormatter

struct MyType: Codable {
    @ISO8601DateCoding
    var myDate: Date // Now encodes to ISO8601
}

@ISO8601DateFormatterCoding<ISO8601DateFormatterStaticCoder>

For other Date formats create a Type that adheres to the ISO8601DateFormatterStaticCoder Protocol and use the convenience @ISO8601DateFormatterCoding typealias or @CodingUses<StaticCoder>.

@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
struct MyCustomISO8601DateFormatter: ISO8601DateFormatterStaticCoder {
    static let iso8601DateFormatter: ISO8601DateFormatter = {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate]
        return formatter
    }()
}


struct MyType: Codable {
    @ISO8601DateFormatterCoding<MyCustomISO8601DateFormatter>
    var myDate: Date // Now encodes with MyCustomISO8601DateFormatter's formatter
}

@NonConformingFloatCoding<ValueProvider>

When using a non-conforming Float, create a Type that adheres to NonConformingDecimalValueProvider and use @NonConformingFloatCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingFloatCoding<MyNonConformingValueProvider>
    var myFloat: Float // Now encodes with the MyNonConformingValueProvider values for infinity/NaN
}

@NonConformingDoubleCoding<ValueProvider>

When using a non-conforming Double, create a Type that adheres to NonConformingDecimalValueProvider and use @NonConformingDoubleCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingDoubleCoding<MyNonConformingValueProvider>
    var myFloat: Float // Now encodes with the MyNonConformingValueProvider values for infinity/NaN
}

Bool Coding

Sometimes an API uses an Int or String for a booleans.

@BoolAsStringCoding

struct MyType: Codable {
    @BoolAsStringCoding
    var myBool: Bool // Now encodes/decodes as a String. `"true"` for `true` and `"false"` for `false`. (Values are lower-cased before decoding)
}

@BoolAsIntCoding

struct MyType: Codable {
    @BoolAsIntCoding
    var myBool: Bool // Now encodes/decodes as an Int. `1` for `true` and `0` for `false`.
}

Additional Customization

The architecture was built with extensibility in mind so Implementing your own custom coding is as simple as adhering to the StaticCoder protocol. You can then simply add @CodingUses<YourCustomCoder> to your property, or create a typealias to make it cleaner: typealias YourCustomCoding = CodingUses<YourCustomCoder>

In fact all the included Wrappers are built the same way!

Full Example

struct NanosecondsSince9170Coder: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Date {
        let nanoSeconds = try Double(from: decoder)
        let seconds = nanoSeconds * 0.000000001
        return Date(secondsSince1970: seconds)
    }

    static func encode(value: Date, to encoder: Encoder) throws {
        let nanoSeconds = value.secondsSince1970 / 0.000000001
        return try nanoSeconds.encode(to: encoder)
    }
}

// Approach 1: CustomCoding
struct MyType: Codable {
    @CodingUses<NanosecondsSince9170Coder>
    var myData: Date // Now uses the NanosecondsSince9170Coder for serialization
}

// Approach 2: CustomEncoding Property Wrapper typealias

typealias NanosecondsSince9170Coding = CodingUses<NanosecondsSince9170Coder>

struct MyType: Codable {
    @NanosecondsSince9170Coding
    var myData: Date // Now uses the NanosecondsSince9170Coder for serialization
}

Take a look at these other examples to see what else is possible.


Property Mutability

In 2.0 all wrappers are Mutable by default and can be made Immutable via Property Wrapper Composition

struct MyType: Codable {
    @Immutable @SecondsSince1970DateCoding
    var createdAt: Date

    @SecondsSince1970DateCoding
    var updatedAt: Date

    mutating func update() {
        createdAt = Date() // ERROR - Cannot assign to property: 'createdAt' is a get-only property
        updatedAt = Date() // Works!
    }
}

Optionals

2.0 introduces @OptionalCoding<StaticCodingWrapper> to enable Optionals for a property.

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var createdAt: Date

    @OptionalCoding<SecondsSince1970DateCoding>
    var updatedAt: Date
}

Only Encoding or Decoding

Sometimes you are only able/wanting to implement Encoding or Decoding.

To enable this, (where practical/possible), all of the included Wrappers have Encoding and Decoding variants

Change Coder to Encoder/Decoder or Coding to Encoding/Decoding to implement only one E.g. @Base64Encoding, @SecondsSince1970DateDecoding, @EncodingUses<ACustomEncoder>, etc.

struct MyType: Encodable {
    @SecondsSince1970DateEncoding
    var myDate: Date
}

struct MyType: Decodable {
    @SecondsSince1970DateDecoding
    var myDate: Date
}

Contributions

If there is a standard Serialization strategy that could be added feel free to open an issue requesting it and/or submit a pull request with the new option.

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].