{"id":19680717,"url":"https://github.com/christophhagen/binarycodable","last_synced_at":"2025-09-07T15:35:12.967Z","repository":{"id":44368873,"uuid":"507057079","full_name":"christophhagen/BinaryCodable","owner":"christophhagen","description":"A binary encoder for Swift Codable types ","archived":false,"fork":false,"pushed_at":"2025-01-12T11:07:28.000Z","size":1310,"stargazers_count":105,"open_issues_count":2,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-30T03:10:54.564Z","etag":null,"topics":["binary","codable","data","decoder","decoding","encoder","encoding","protobuf","protobuf3","protocol-buffers","serialization","swift"],"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/christophhagen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License.md","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":"2022-06-24T15:22:17.000Z","updated_at":"2025-03-03T12:30:21.000Z","dependencies_parsed_at":"2024-01-16T21:36:55.328Z","dependency_job_id":"d1426913-d775-49f3-bdea-c64f2590a361","html_url":"https://github.com/christophhagen/BinaryCodable","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophhagen%2FBinaryCodable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophhagen%2FBinaryCodable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophhagen%2FBinaryCodable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophhagen%2FBinaryCodable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/christophhagen","download_url":"https://codeload.github.com/christophhagen/BinaryCodable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430966,"owners_count":20937875,"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":["binary","codable","data","decoder","decoding","encoder","encoding","protobuf","protobuf3","protocol-buffers","serialization","swift"],"created_at":"2024-11-11T18:05:51.270Z","updated_at":"2025-09-07T15:35:12.951Z","avatar_url":"https://github.com/christophhagen.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"assets/logo.png\" width=\"500\" max-width=\"90%\" alt=\"BinaryCodable\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"assets/swift.svg\" /\u003e \u003c!-- https://img.shields.io/badge/Swift-5.6--5.10-orange.svg --\u003e\n    \u003cimg src=\"assets/platforms.svg\" /\u003e \u003c!-- https://img.shields.io/badge/Platforms-iOS_|_macOS_|_Linux_|_tvOS_|_watchOS-green.svg --\u003e\n    \u003ca href=\"https://github.com/christophhagen/BinaryCodable/actions/workflows/tests.yml\" style=\"text-decoration: none;\"\u003e\n        \u003cimg src=\"https://github.com/christophhagen/BinaryCodable/actions/workflows/tests.yml/badge.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://docs.christophhagen.de/documentation/binarycodable\" style=\"text-decoration: none;\"\u003e\n        \u003cimg src=\"assets/docs.svg\" /\u003e \u003c!-- https://img.shields.io/badge/documentation-100%25-green.svg --\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nThis package provides convenient encoding and decoding to/from binary data for all Swift `Codable` types. \n\n## Use cases\n\nThere are only few encoders and decoders available for Swift's Codable format, and Apple provides a [JSONEncoder](https://developer.apple.com/documentation/foundation/jsonencoder) and a [PropertyListEncoder](https://developer.apple.com/documentation/foundation/propertylistencoder) for basic encoding. While these can cover some use cases (especially when interacting with Web Content through JSON), they lack encoding efficiency when designing APIs within an ecosystem. JSON, for example, is notoriously inefficient when it comes to binary data.\n\nOne very popular alternative for binary data are Google's [Protocol Buffers](https://developers.google.com/protocol-buffers), which offer broad support across different platforms and programming languages. But they don't support Swift's `Codable` protocol, and thus require manual message definitions, the Protobuf compiler, and a lot of copying between data structures during encoding and decoding.\n\nSo if you're looking for a decently efficient binary encoder in a pure Swift project, then `BinaryCodable` may be right for you. Simply make your `struct`s (or classes!) conform to `Codable`, and `BinaryCodable` does the rest!\n\n### Alternatives\n\n#### [Protocol Buffers](https://developers.google.com/protocol-buffers)\nEfficient binary format, and broad support across different platforms and programming languages.\nMuch more limited than `Codable` in terms of allowed types. \nMessage definitions must be written in separate files and compiled to Swift code.\nThe library for swift is [swift-protobuf](https://github.com/apple/swift-protobuf).\n\n#### [ProtobufCodable](https://github.com/christophhagen/ProtobufCodable)\nA `Codable`-compatible implementation of the Protocol Buffer binary format.\nIt has the same limitations on the allowed types as [swift-protobuf](https://github.com/apple/swift-protobuf), but message definitions can be written directly in Swift.\nSlower during encoding and decoding than `swift-protobuf`.\n\n#### [LegacyBinaryCodable](https://christophhagen.de/LegacyBinaryCodable)\n\nA mirror of the older V2 version of `BinaryCodable`, which should only be used to migrate encoded data to a different format.\n\n#### [CBORCoding](https://github.com/SomeRandomiOSDev/CBORCoding)\nIf you're looking for a `Codable`-compatible alternative which is also available on other platforms, with a well-defined [spec](https://cbor.io). \nIt appears to have nearly the same encoding efficiency as `BinaryCodable`.\nSuffers from the [double-optional bug](#double-optional-bug).\n\n#### [PotentCodables](https://github.com/outfoxx/PotentCodables)\nAlso offers CBOR encoding for `Codable` types, plus a bunch of other things related to `Codable`.\nSuffers from the [double-optional bug](#double-optional-bug).\n\n#### [Swift BSON](https://github.com/mongodb/swift-bson)\nEncoding according to the [BSON specification](https://bsonspec.org). \nLess efficient binary represenation than Protocol Buffers and `BinaryCodable`, but mature. \nUsed for MongoDB. There is also [another implementation](https://github.com/orlandos-nl/BSON).\n\n#### [JSONEncoder](https://developer.apple.com/documentation/foundation/jsonencoder)/[JSONDecoder](https://developer.apple.com/documentation/foundation/jsondecoder)\nThe `Foundation` module provides JSON encoding, which is String-based and therefore not efficient.\nAlso has the [double-optional bug](#double-optional-bug).\n\n## Installation\n\n### Swift Package Manager\n\nSimply include in your `Package.swift`:\n```swift\ndependencies: [\n    .package(url: \"https://github.com/christophhagen/BinaryCodable\", from: \"3.0.0\")\n],\ntargets: [\n    .target(name: \"MyTarget\", dependencies: [\n        .product(name: \"BinaryCodable\", package: \"BinaryCodable\")\n    ])\n]\n```\n\n### Xcode project\n\nSelect your `Project`, navigate to the `Package Dependencies` tab, and add `https://github.com/christophhagen/BinaryCodable` using the `+` button.\n\n## Usage\n\nDocumentation of the library is available [here](https://docs.christophhagen.de/documentation/binarycodable) (generated using [Swift DocC](https://www.swift.org/documentation/docc)).\n\n### First steps\n\nLet's assume a message definition: \n\n```swift\nstruct Message: Codable {\n\n    var sender: String\n    \n    var isRead: Bool\n    \n    var unreadCount: Int\n}\n```\n\nSimply import the module where you need to encode or decode a message:\n\n```swift\nimport BinaryCodable\n```\n\n### Encoding\n\nConstruct an encoder when converting instances to binary data, and feed the message(s) into it:\n\n```swift\nlet message: Message = ...\n\nlet encoder = BinaryEncoder()\nlet data = try encoder.encode(message)\n```\n\nIt's also possible to encode single values, arrays, optionals, sets, enums, dictionaries, and more, so long as they conform to `Codable`.\n\n### Decoding\n\nDecoding instances from binary data works much the same way:\n\n```swift\nlet decoder = BinaryDecoder()\nlet message = try decoder.decode(Message.self, from: data)\n```\n\nAlternatively, the type can be inferred:\n\n```swift\nlet message: Message = try decoder.decode(from: data)\n```\n\n### Custom encoding and decoding\n\n`BinaryCodable` supports the use of custom encoding and decoding routines by implementing `encode(to:)` and `init(from:)`.\n\nThere is only one aspect that's handled differently than the `Codable` documentation specifies, which is the explicit encoding of `nil` in keyed containers.\nCalling `encodeNil(forKey:)` on a keyed container has no effect, there is no explicit `nil` value encoded for the key.\nThis results in the `contains()` function during decoding returning `false` for the key.\nThis is different to e.g. JSON, where calling `encodeNil(forKey:)` would cause the following encoding:\n\n```json\n{ \n    \"myProperty\" : null\n}\n```\n\nThe implementation of `encodeNil(forKey:)` and `decodeNil(forKey:)` handles this case differently, because the alternatives are not optimal:\nIt would be possible to explicitly encode `nil` for a key, but this would cause problems with double optionals in structs (e.g. Int??), which could no longer distinguish between `.some(nil)` and `nil`.\nTo fix this issue, an additional `nil` indicator would be needed for **all** values in keyed containers, which would decrease the efficiency of the binary format. \nThat doesn't seem reasonable just to support a rarely used feature, since `encodeNil(forKey:)` is never called for automatically synthesized Codable conformances.\n\nThe recommendation therefore is to use `encodeIfPresent(_, forKey:)` and `decodeIfPresent(_, forKey:)`.\nAnother option would be to use a double optional, since this is basically the information `encodeNil` provides: `nil`, if the key is not present, `.some(nil)`, if the key is present with `nil`, and `value`, if the key is present with a value.\n\n### Errors\n\nIt's possible for both encoding and decoding to fail. \nEncoding can produce `EncodingError` errors, while unsuccessful decoding produces `DecodingError`s. \nBoth are the default Errors provided by Swift, supplied with additional information describing the nature of the error. \nSee the documentation of the types to learn more about the different error conditions.\n\n#### Handling corrupted data\n\nThe [binary format](BinaryFormat.md) provides no provisions to detect data corruption, and various errors can occur as the result of added, changed, or missing bytes and bits. \nAdditional external measures (checksums, error-correcting codes, ...) should be applied if there is an increased risk of data corruption.\n\nAs an example, consider the simple encoding of a `String` inside a `struct`, which consists of a `key` followed by the length of the string in bytes, and the string content.\nThe length of the string is encoded using variable-length encoding, so a single bit flip (in the MSB of the length byte) could result in a very large `length` being decoded, causing the decoder to wait for a very large number of bytes to decode the string.\nThis simple error would cause much data to be skipped, potentially corrupting the data stream indefinitely.\nAt the same time, it is not possible to determine *with certainty* where the error occured, making error recovery difficult without additional information about boundaries between elements.\n\nThe decoding errors provided by the library are therefore only hints about errors likely occuring from non-conformance to the binary format or version incompatibility, which are not necessarily the *true* causes of the failures when data corruption is present.\n\n### Coding Keys\n\nThe `Codable` protocol uses [`CodingKey`](https://developer.apple.com/documentation/swift/codingkey) definitions to identify properties of instances. \nBy default, coding keys are generated using the string values of the property names.\n\nSimilar to JSON encoding, `BinaryCodable` can embed the property names in the encoded data.\n\nUnlike JSON (which is human-readable), the binary representation produced by `BinaryCodable` is intended for cases when efficient encoding is important. \n`Codable` allows the use of integer keys for each property, which significantly increases encoding efficiency. \nYou can specify integer keys by adding an `Int` enum conforming to the `CodingKey` protocol to the `Codable` type:\n\n```swift\nstruct Message: Codable {\n\n    var sender: String\n    \n    var isRead: Bool\n    \n    var unreadCount: Int\n    \n    // Assign an integer to each property\n    enum CodingKeys: Int, CodingKey {\n        case sender = 1\n        case isRead = 2\n        case unreadCount = 3\n    }\n}\n```\nThe enum must have a raw value of either `Int` or `String`, and the cases must match the property names within the type (it is possible to omit keys for properties which should not be encoded).\n\nUsing integer keys can significantly decrease the binary size, especially for long property names. \nAdditionally, integer keys can be useful when intending to store the binary data persistently. \nChanges to property names can be performed in the code without breaking the decoding of older data (although this can also be achieved with custom `String` keys).\n\nNotes: \n- Negative values for integer keys are **not** supported.\n- Small integer keys produce the smallest binary sizes.\n- The `0` integer key shouldn't be used, since it is also used internally when encoding `super`.\n- The allowed range for integer keys is from `0` (inclusive) to `Int64.max` (inclusive).\n\n### Property wrappers\n\n#### Fixed size integers\n\nWhile varints are efficient for small numbers, their encoding introduces a storage and computation penalty when the integers are often large, e.g. for random numbers. \n`BinaryCodable` provides the `@FixedSizeEncoded` property wrapper, which forces integers to be encoded using their little-endian binary representations. \nThis means that e.g. an `Int32` is always encoded as 4 byte (instead of 1-5 bytes using Varint encoding). \nThis makes 32-bit `FixedSizeEncoded` types more efficient than `Varint` if values are often larger than `2^28` (`2^56` for 64-bit types).\n\nUse the property wrapper within a `Codable` definition to enforce fixed-width encoding for a property:\n```swift\nstruct MyStruct: Codable {\n\n    /// Always encoded as 4 bytes\n    @FixedSizeEncoded\n    var largeInteger: Int32\n}\n```\n \nThe `FixedSize` wrapper is available for `Int`, `Int32`, `Int64`, `UInt`, `UInt32`, and `UInt64`.\nIt has no effect for `Int16` and `UInt16`, which are already encoded with a fixed size by default.\n \n#### Variable length integers\n \nSome integers can be forced to use variable-length encoding instead of fixed-size or zig-zag encoding using the `@VariableLengthEncoded` property wrapper.\n\nFor `Int16` and `UInt16` (normally fixed-size encoded), this encoding can be more efficient if values are often smaller than `128` for `UInt16` and `63` for `Int16`.\nFor `Int`, `Int32` and `Int64` (normally zig-zag encoded), the encoding is (marginally) more efficient if values are mostly positive.\nFor `UInt`, `UInt32`, and `UInt64` the wrapper has no effect.\n\n```swift\nstruct MyStruct: Codable {\n\n    /// Efficient for small, positive numbers\n    @VariableLengthEncoded \n    var value: Int16\n}\n```\n\n#### Zig-Zag encoded integers\n\nThe signed integers `Int`, `Int32` and `Int64` are encoded using zig-zag encoding, which is more efficent than variable-length encoding if numbers are negative.\nThe `@ZigZagEncoded` wrapper can force `Int16` types to use zig-zag encoding instead of fixed-size encoding, which is more efficient for small (positive and negative) numbers.\nThe encoding is more efficient if values are between `-64` and `63`.\nFor `Int`, `Int32` and `Int64` the wrapper has no effect.\n\n```swift\nstruct MyStruct: Codable {\n\n    /// More efficient between `-64` and `63`.\n    @ZigZagEncoded \n    var value: Int16\n}\n```\n\n### Options\n\n#### Sorting keys\n\nThe `BinaryEncoder` provides the `sortKeysDuringEncoding` option, which forces fields in \"keyed\" containers, such as `struct` properties (and some dictionaries), to be sorted in the binary data. \nThis sorting is done by using either the [integer keys](#coding-keys) (if defined), or the property names. \nDictionaries with `Int` or `String` keys are also sorted. \n\nSorting the binary data does not influence decoding, but introduces a computation penalty during encoding. \nIt should therefore only be used if the binary data must be consistent across multiple invocations.\n\n**Note:** The `sortKeysDuringEncoding` option does **not** guarantee deterministic binary data, and should be used with care.\nElements of any non-ordered types (Sets, Dictionaries) will appear in random order in the binary data.\n\n### Stream encoding and decoding\n\nThe library provides the option to perform encoding and decoding of continuous streams, such as when writing sequences of elements to a file, or when transmitting data over a network.\nThis functionality can be used through `BinaryStreamEncoder` and `BinaryStreamDecoder`, causing the encoder to embed additional information into the data to allow continuous decoding (mostly length information).\nEncoding and decoding is always done with sequences of one specific type, since multiple types in one stream could not be distinguished from one another.\n\nEncoding of a stream works similarly to normal encoding:\n\n```swift\nlet encoder = BinaryStreamEncoder\u003cInt\u003e()\nlet chunk1 = try encoder.encode(1)\nlet chunk2 = try encoder.encode(contentsOf: [2,3])\n...\n\nlet data = chunk1 + chunk2 + ...\n```\n\nDecoding of the individual chunks, with the decoder returning all elements which can be decoded using the currently available data.\n\n```swift\nlet decoder = BinaryStreamDecoder\u003cInt\u003e()\nlet decoded1 = try decoder.decode(chunk1)\nprint(decoded1) // [1]\n\nlet decoded2 = try decoder.decode(chunk2)\nprint(decoded2) // [2,3]\n```\n\nThe decoder has an internal buffer, so incomplete data can be inserted into the decoder as it becomes available. The output of `decode(_ data:)` will be empty until the next complete element is processed.\n\n### File encoding and decoding \n\nWriting data streams to files is a common use case, so the library also provides wrappers around `BinaryStreamEncoder` and `BinaryStreamDecoder` to perform these tasks.\nThe `BinaryFileEncoder` can be used to sequentially write elements to a file:\n\n```swift\nlet encoder = BinaryFileEncoder\u003cDataElement\u003e(fileAt: url)\ntry encoder.write(element1)\ntry encoder.write(element2)\n...\ntry encoder.close() // Close the file\n```\n\nElements will always be appended to the end of file, so existing files can be updated with additional data.\n\nDecoding works in a similar way, except with a callback to handle each element as it is decoded:\n```swift\nlet decoder = BinaryFileDecoder\u003cDataElement\u003e(fileAt: url)\ntry decoder.read { element in\n    // Process each element\n}\n```\n\nThere is also the possibility to read all elements at once using `readAll()`, or to read only one element at a time (`readElement()`).\n\n### Detailed behaviour on custom encoding\n\nThere are a few notable details regarding custom implementations of `func encode(to encoder: any Encoder) throws` and `init(from decoder: any Decoder) throws` that are worth mentioning.\nSometimes the expected behaviour is not clear, so this implementation attempts to mimic the behaviour of `JSONEncoder` and `JSONDecoder`.\n\n#### Multiple calls to containers\n\nIt's possible to perform repeated calls to functions on `Encoder`, but only of the same type:\n\n```swift\nfunc encode(to encoder: any Encoder) throws {\n    var container1 = encoder.unkeyedContainer()\n    var container2 = encoder.unkeyedContainer() // valid\n    \n    var other = encoder.singleValueContainer() // crashes\n}\n```\n\nThe values encoded to these multiple instances is the following:\n- Single value containers: the last encoded value is used\n- Unkeyed containers: Values are placed in order of insertion, independent of the container used\n- Keyed containers: The last value assigned for each key is used\n\nNote: For keyed containers, it is possible to use multiple containers with different `Key` types,\nthat insert keys to the same underlying storage:\n\n```swift\nfunc encode(to encoder: any Encoder) throws {\n    var container1 = encoder.container(keyedBy: KeySetA.self)\n    var container2 = encoder.container(keyedBy: KeySetB.self)\n    \n    try container1.encode(\"ABC\", forKey: KeySetA.value)\n    try container1.encode(\"abc\", forKey: KeySetB.value) // Overwrites \"ABC\"\n}\n```\n\nDuring decoding, the behaviour is slightly different.\n\nIt is allowed to treat a `Decoder` as multiple types at once:\n\n```swift\ninit(from decoder: any Decoder) throws {\n    let keyed = try decoder.container(keyedBy: CodingKeys.self)\n    self.a = try keyed.decode(String.self, forKey: .a)\n    let single = try decoder.singleValueContainer()\n    let dict = try single.decode([String : String].self) // Treat keyed container as dictionary\n    self.b = dict[\"b\"]!\n}\n```\n\nMultiple unkeyed containers during decoding do not synchronize their state:\n\n```swift\ninit(from decoder: any Decoder) throws {\n    // Assuming values [\"123\", \"ABC\"]\n    let container1 = try decoder.unkeyedContainer()\n    let container2 = try decoder.unkeyedContainer()\n    let first = container1.decode(String.self) // Returns \"123\"\n    let other = container2.decode(String.self) // Returns \"123\"\n    let second = container1.decode(String.self) // Returns \"ABC\"\n}\n```\n\nThis may be slighly confusing given the different behaviour during encoding,\nbut matches the implementation of `JSONDecoder`.\n\n## Binary format\n\nTo learn more about the encoding format, see [BinaryFormat.md](BinaryFormat.md).\n\n### Double-optional bug\n\nThere is an edge case that many decoders handle incorrectly: Double optionals, like `Int??`.\nWhile `BinaryCodable` handles this case correctly (see [test](https://github.com/christophhagen/BinaryCodable/blob/0cd135eccf2e6e7dd0846883bac1ccb6c48ee0a3/Tests/BinaryCodableTests/OptionalEncodingTests.swift#L21)), there are many encoders that don't.\nEven the standard `JSONEncoder` has this issue:\n\n```swift\nlet value: Int?? = .some(.none)\nlet encoded = try JSONEncoder().encode(value)\nlet decoded = try JSONDecoder().decode(Int??.self, from: encoded)\nprint(value == decoded) // Prints \"false\"\n```\n\nThis issue arises from the fact that many encoding formats can't properly handle double optionals, e.g. for JSON, both `.some(.none)` and `.none` will produce the String `none`, so the decoder can't distinguish between the two cases and will decode as `.none`.\nThis bug affects at least the following Encoders for `Codable` types:\n- [JSONEncoder](https://developer.apple.com/documentation/foundation/jsonencoder)/[JSONDecoder](https://developer.apple.com/documentation/foundation/jsondecoder) from the Foundation module\n- [CBORCoding](https://github.com/SomeRandomiOSDev/CBORCoding)\n- [PotentCodables](https://github.com/outfoxx/PotentCodables)\n\n## Legacy versions and migration\n\nVersion 3 of `BinaryCodable` has significantly changed the binary format, which means that the two versions are **not** cross-compatible.\nThe [format](BinaryFormat.md) was changed to provide support for all `Codable` features, which was not possible with the previous format, that was adapted from [Protocol Buffers](https://developers.google.com/protocol-buffers).\nThe redesign of the library also reduced code complexity and size, which lead to some speed improvements and greater reliability.\n\nThe support for interoperability with [Protocol Buffers](https://developers.google.com/protocol-buffers) was also dropped, since the binary formats are no longer similar.\nThe functionality was extracted to a separate library called [ProtobufCodable](https://github.com/christophhagen/ProtobufCodable).\n\n### Migrating from 2.x to 3.0\n\nTo convert data from the [legacy format](LegacyFormat) to the new version, the data has to be decoded with version 2 and re-encoded with version 3.\nThe Swift Package Manager currently doesn't allow to include the same dependency twice (with different versions), so the legacy version has been stripped down to the essentials and is provided as the stand-alone package [LegacyBinaryCodable](https://christophhagen.de/LegacyBinaryCodable).\nIt only allows decoding, and can be integrated as a separate dependency:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/christophhagen/BinaryCodable\", from: \"3.0.0\"),\n        .package(url: \"https://github.com/christophhagen/LegacyBinaryCodable\", from: \"2.0.0\"),\n    \n],\ntargets: [\n    .target(name: \"MyTarget\", dependencies: [\n        .product(name: \"BinaryCodable\", package: \"BinaryCodable\"),\n        .product(name: \"LegacyBinaryCodable\", package: \"LegacyBinaryCodable\")\n    ])\n]\n```\n\nIn the code, you can then decode and re-encode:\n\n```swift\nimport BinaryCodable\nimport LegacyBinaryCodable\n\nfunc reencode\u003cT\u003e(data: Data, as type: T.Type) throws -\u003e Data where T: Codable {\n    let decoder = LegacyBinaryDecoder()\n    let value = try decoder.decode(T.self, from data: Data)\n    let encoder = BinaryEncoder()\n    return try encoder.encode(value)\n}\n```\n\n## Tests\n\nThe library comes with an extensive test suite, which checks that encoding works correctly for many cases. \nThese tests can be executed using ```swift test``` from the package root, or when opening the package using Xcode.\n\n## License\n\nMIT. See [License.md](License.md)\n\n## Roadmap\n\n### Additional tests\n\nWhile the test suite covers many cases, there is no complete code coverage.\nEspecially the bahaviour in error conditions can use additional testing to ensure that there are no edge cases where the program crashes, or does some other weird thing.\n\n### Speed\n\nOne option could be to use a common data storage during encoding and decoding, so that the individual containers can be converted to `struct`s to make them more lightweight. It may also be possible to prevent some unnecessary data copying.\n\nIncreasing the speed of the encoding and decoding process is not a huge priority at the moment. \nIf you have any pointers on how to improve the performance further, feel free to contribute.\n\n## Contributing\n\nUsers of the library are encouraged to contribute to this repository.\n\n### Feature suggestions\n\nPlease file an issue with a description of the feature you're missing. Check other open and closed issues for similar suggestions and comment on them before creating a new issue.\n\n### Bug reporting\n\nFile an issue with a clear description of the problem. Please include message definitions and other data where possible so that the error can be reproduced.\n\n### Documentation\n\nIf you would like to extend the documentation of this library, or translate the documentation into other languages, please also open an issue, and I'll contact you for further discussions.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophhagen%2Fbinarycodable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristophhagen%2Fbinarycodable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophhagen%2Fbinarycodable/lists"}