CBOR is a lightweight implementation of the CBOR (Concise Binary Object Representation) format in Swift. It allows you to encode and decode data to and from the CBOR format, work directly with the CBOR data model, and integrate with Swift’s Codable
protocol.
Direct CBOR Data Model:
Represent CBOR values using an enum with cases for unsigned/negative integers, byte strings, text strings, arrays, maps (ordered key/value pairs), tagged values, simple values, booleans, null, undefined, and floats.
Encoding & Decoding:
Easily convert between CBOR values and byte arrays.
CBOREncoder
and CBORDecoder
for complete support of Swift’s Codable
protocol, including:
CBORError
) to help you diagnose encoding/decoding issues.Comprehensive documentation is available via DocC:
swift package --allow-writing-to-directory ./docs generate-documentation --target CBOR
Add the CBOR package to your Swift package dependencies:
// swift-tools-version:6.0
import PackageDescription
let package = Package(
name: "YourProject",
dependencies: [
.package(url: "https://github.com/apache-edge/cbor.git", from: "0.0.2")
],
targets: [
.target(
name: "YourTarget",
dependencies: [
.product(name: "CBOR", package: "cbor")
]
)
]
)
import CBOR
// Create a CBOR value (an unsigned integer)
let cborValue: CBOR = .unsignedInt(42)
// Encode the CBOR value to a byte array
let encodedBytes = cborValue.encode()
print("Encoded bytes:", encodedBytes)
// Decode the bytes back into a CBOR value
do {
let decodedValue = try CBOR.decode(encodedBytes)
print("Decoded CBOR value:", decodedValue)
} catch {
print("Decoding error:", error)
}
import CBOR
import Foundation
// Define your data structures
struct Person: Codable {
let name: String
let age: Int
let addresses: [Address]
let metadata: [String: String]
}
struct Address: Codable {
let street: String
let city: String
}
// Create an instance
let person = Person(
name: "Alice",
age: 30,
addresses: [
Address(street: "123 Main St", city: "Wonderland"),
Address(street: "456 Side Ave", city: "Fantasialand")
],
metadata: [
"occupation": "Engineer",
"department": "R&D"
]
)
// Encode to CBOR
do {
let encoder = CBOREncoder()
let cborData = try encoder.encode(person)
print("Encoded CBOR Data:", cborData as NSData)
// Decode back from CBOR
let decoder = CBORDecoder()
let decodedPerson = try decoder.decode(Person.self, from: cborData)
print("Decoded Person:", decodedPerson)
} catch {
print("Error:", error)
}
// Create an array of CBOR values
let arrayCBOR: CBOR = .array([
.unsignedInt(1),
.textString("hello"),
.bool(true)
])
// Create a map (ordered key/value pairs)
let mapCBOR: CBOR = .map([
CBORMapPair(key: .textString("name"), value: .textString("SwiftCBOR")),
CBORMapPair(key: .textString("version"), value: .unsignedInt(1))
])
// Combine them into a nested structure
let nestedCBOR: CBOR = .map([
CBORMapPair(key: .textString("data"), value: arrayCBOR),
CBORMapPair(key: .textString("info"), value: mapCBOR)
])
do {
let cbor = try CBOR.decode([0xff, 0x00]) // Example invalid CBOR data
} catch let error as CBORError {
switch error {
case .invalidCBOR:
print("Invalid CBOR data")
case .typeMismatch(let expected, let actual):
print("Type mismatch: expected \(expected), found \(actual)")
case .prematureEnd:
print("Unexpected end of data")
default:
print("Other CBOR error:", error.description)
}
} catch {
print("Unexpected error:", error)
}
// Example of nested containers and arrays
struct Team: Codable {
let name: String
let members: [Member]
let stats: Statistics
let tags: Set<String>
}
struct Member: Codable {
let id: Int
let name: String
let roles: [Role]
enum Role: String, Codable {
case developer
case designer
case manager
}
}
struct Statistics: Codable {
let projectsCompleted: Int
let averageRating: Double
let activeYears: [Int]
}
// Create and encode a team
let team = Team(
name: "Dream Team",
members: [
Member(id: 1, name: "Alice", roles: [.developer, .manager]),
Member(id: 2, name: "Bob", roles: [.designer])
],
stats: Statistics(
projectsCompleted: 12,
averageRating: 4.8,
activeYears: [2020, 2021, 2022]
),
tags: ["innovative", "agile", "productive"]
)
let encoder = CBOREncoder()
let cborData = try encoder.encode(team)
import CBOR
// Define a struct with Set properties
struct SetContainer: Codable, Equatable {
let stringSet: Set<String>
let intSet: Set<Int>
}
// Create an instance with sets
let setExample = SetContainer(
stringSet: Set(["apple", "banana", "cherry"]),
intSet: Set([1, 2, 3, 4, 5])
)
// Encode to CBOR
let encoder = CBOREncoder()
let encoded = try encoder.encode(setExample)
// Decode from CBOR
let decoder = CBORDecoder()
let decoded = try decoder.decode(SetContainer.self, from: encoded)
// Verify sets are preserved
assert(decoded.stringSet.contains("apple"))
assert(decoded.intSet.contains(3))
import CBOR
// Define a struct with optional and nested optional properties
struct OptionalExample: Codable, Equatable {
let simpleOptional: String?
let nestedOptional: Int??
let optionalArray: [Double?]?
let optionalDict: [String: Bool?]?
}
// Create an instance with various optional values
let optionalExample = OptionalExample(
simpleOptional: "present",
nestedOptional: nil,
optionalArray: [1.0, nil, 3.0],
optionalDict: ["yes": true, "no": false, "maybe": nil]
)
// Encode to CBOR
let encoder = CBOREncoder()
let encoded = try encoder.encode(optionalExample)
// Decode from CBOR
let decoder = CBORDecoder()
let decoded = try decoder.decode(OptionalExample.self, from: encoded)
// Verify optionals are preserved
assert(decoded.simpleOptional == "present")
assert(decoded.nestedOptional == nil)
assert(decoded.optionalArray?[1] == nil)
assert(decoded.optionalDict?["maybe"] == nil)
import CBOR
// Define an enum to use as dictionary keys
enum Color: String, Codable, Hashable {
case red
case green
case blue
}
struct EnumKeyDict: Codable, Equatable {
let colorValues: [Color: Int]
}
// Create an instance with enum keys
let colorDict = EnumKeyDict(colorValues: [
.red: 1,
.green: 2,
.blue: 3
])
// Encode to CBOR
let encoder = CBOREncoder()
let encoded = try encoder.encode(colorDict)
// Decode from CBOR
let decoder = CBORDecoder()
let decoded = try decoder.decode(EnumKeyDict.self, from: encoded)
// Verify dictionary with enum keys is preserved
assert(decoded.colorValues[.red] == 1)
assert(decoded.colorValues[.green] == 2)
assert(decoded.colorValues[.blue] == 3)
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.