Swift Package Index 的标志。Swift Package Index

追踪 Swift 6 严格并发检查在数据竞争安全方面的采用情况。有多少 packages 为 Swift 6 做好准备

当使用 Xcode 项目时

当使用 Swift Package Manager 清单时

选择 package 版本

0.4.0

master


一个用于 Swift 的 CBOR 实现




unlicense

SwiftCBOR

Swift 中的 CBOR (RFC 7049 Concise Binary Object Representation,精简二进制对象表示) 解码器和编码器。可以直接从 Swift 类型进行编码,或使用包装器对象。解码为 CBOR 值类型,可以使用原生 Swift 下标进行访问,并使用等效的字面量表示。

  • 一个完全跨平台的 Swift 5.x 包!
  • 支持 Codable
  • 负整数被解码为 NegativeInt(UInt),实际数字为 -1 - i(CBOR 的负整数可以大于 64 位有符号整数)。
  • 标签被解码,但不被处理。带标签的值被编码,但不进行类型检查。自己处理吧 :-)
  • 字面量可转换类型已为 CBOR 类型定义!
  • 还有 subscript。因此您可以像这样访问 CBOR 映射和数组:myDecodedObject["numbers"][1]
  • 如果您想从流中解码,请在您的流上实现 CBORInputStream 协议,并像这样创建解码器:CBORDecoder(stream: yourStream)
  • 半精度浮点数可以解码为 Float,甚至可能正确。不支持编码 Float16(Swift 中不存在)。
  • 编码的内存效率需要调整。(编码通常不是就地完成的。)
  • 支持编码不定长度数据,但您需要显式地将开始和结束信息添加到您的流数据中。
  • 推荐使用 cbor.me 来查看您的 CBOR 编码数据。

安装

有很多方法:Swift Package Manager、CocoaPods、git submodule...

CocoaPod 由贡献者提交,更新可能会有所延迟。

Swift Package Manager 是推荐的依赖管理器。

解码

import SwiftCBOR

let decoded = try! CBOR.decode([0x9f, 0x18, 255, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 0x18, 1, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0xff])
print(decoded)
// CBOR.array([CBOR.unsignedInt(255), CBOR.array([CBOR.unsignedInt(1), CBOR.utf8String("ABC")]), CBOR.utf8String("ABC")])

要解包解码后的 CBOR 值,请使用 模式匹配!!

编码

编码一个值会返回一个字节数组,[UInt8]。您可以使用 CBOR.encode(myValue)myValue.encode() 进行编码。任何符合 CBOREncodable 协议的类型都可以被编码。您可以为您的类型实现 CBOREncodable 协议,然后像往常一样进行编码。

CBOR.encode(100)  // --> [0x18, 0x64] of type [UInt8]
Int(100).encode() // --> [0x18, 0x64]. Int conforms to the CBOREncodable protocol
"hello".encode()  // --> [0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f]. So does String
CBOR.encode(["a", "b", "c"])

let byteString: [UInt8] = [0x01, 0x02]
CBOR.encode(byteString, asByteString: true)

由于 Swift 不完整的泛型系统,您不能调用 someArray.encode()someDictionary.encode(),但只要您的数组项或映射的键和值类型符合 CBOREncodable,您就可以简单地使用 CBOR.encode(someArrayOrMap)

在某些情况下,可能需要在编码之前创建一个 CBOR 中间表示。例如,如果您想编码包含异构类型的数组或字典(这在类似 JSON 的对象中很常见),您还不能使用原生 Swift 映射。 您可以在您的类型上实现 CBOREncodable,这将构建一个 CBOR 值并对其进行编码,或者在没有 CBOREncodable 的情况下进行 CBOR 值处理。

CBOR 枚举可以 使用字面量表示,但请注意变量不是字面量,因此您可能需要手动调用构造函数。

public protocol CBOREncodable {
    func encode(options: CBOROptions) -> [UInt8]
}

struct MyStruct: CBOREncodable {
    var x: Int
    var y: String

    public func encode(options: CBOROptions = CBOROption()) -> [UInt8] {
        let cborWrapper: CBOR = [
            "x": CBOR(integerLiteral: self.x), // You can use the literal constructors
            "y": CBOR.utf8String(self.y), // Or the enum variants
            "z": 123 // Or literals
        ]
        return cborWrapper.encode()
    }
}

MyStruct(x: 42, y: "words").encode()
// --> bytes (as hex): a2 61 79 65 77 6f 72 64 73 61 78 18 2a

encode 函数不必一定是那样的。如果您想做一些自定义的事情,比如保持映射键的顺序,您可以手动构建 [UInt8]。可以参考 Encoder 函数 获取灵感。

编码 API

当前的通用 API 如下所示。当您需要对要编码的类型进行细粒度控制时,请使用以下方法。

func encode<T: CBOREncodable>(_ value: T) -> [UInt8]
func encode<A: CBOREncodable, B: CBOREncodable>(_ dict: [A: B]) -> [UInt8]

// NOTE: Please see the note on encoding byte strings at the end of this readme.
func encode<T: CBOREncodable>(_ array: [T], asByteString: Bool = false) -> [UInt8]

/// Only needed for fine-grained control:
func encodeUInt{8, 16, 32, 64}(_ x: UInt8) -> [UInt8]
func encodeNegativeInt(_ x: Int) -> [UInt8]
func encodeByteString(_ bs: [UInt8]) -> [UInt8] // does no endian interpretation
func encodeString(_ str: String) -> [UInt8]
func encodeArray<T: CBOREncodable>(_ arr: [T]) -> [UInt8]
func encodeMap<A: CBOREncodable, B: CBOREncodable>(_ map: [A: B]) -> [UInt8]
func encodeTagged<T: CBOREncodable>(tag: UInt8, value: T) -> [UInt8]
func encodeSimpleValue(_ x: UInt8) -> [UInt8]
func encode{Null, Undefined, Break}() -> [UInt8]
func encodeFloat(_ x: Float) -> [UInt8]
func encodeDouble(_ x: Double) -> [UInt8]
func encodeBool(_ x: Bool) -> [UInt8]

不定长度数据

要编码不定长度的数组、映射、字符串和字节字符串,请显式使用 open- 和 close-stream CBOR 值。在这两个值之间,使用编码后的数组和映射,通过 CBOR.encodeArrayChunkCBOR.encodeMapChunk。 不定长度的字符串和字节字符串可以像正常编码一样编码(即,它们不需要自己的“块”函数)。

let map: [String: Int] = ["a": 1]
let map2 = ["B": 2]
CBOR.encodeMapStreamStart() + CBOR.encodeMapChunk(map) + CBOR.encodeMapChunk(map2) + CBOR.encodeStreamEnd()

let bs: [UInt8] = [0xf0]
let bs2: [UInt8] = [0xff]
CBOR.encodeByteStringStreamStart()
    + CBOR.encode(bs, asByteString: true)
    + CBOR.encode(bs2, asByteString: true)
    + CBOR.encodeStreamEnd()

// Current stream-encoding API:
func encodeArrayStreamStart() -> [UInt8]
func encodeMapStreamStart() -> [UInt8]
func encodeStringStreamStart() -> [UInt8]
func encodeByteStringStreamStart() -> [UInt8]
func encodeStreamEnd() -> [UInt8] // Equal to CBOR.encodeBreak()
func encodeArrayChunk<T: CBOREncodable>(_ chunk: [T]) -> [UInt8]
func encodeMapChunk<A: CBOREncodable, B: CBOREncodable>(_ map: [A: B]) -> [UInt8]

关于字节序反转的说明

最后,关于在使用通用数组编码器 CBOR.encode(..) 时编码字节字符串的技术说明。 如果函数参数 asByteString 为真,那么除了 UInt8 之外的所有类型的数组,如果计算机是小端字节序(CBOR 使用大端字节序或网络字节序),则每个项目的原始字节将被反转(但不会反转项目本身的顺序)。 UInt8 的数组被认为已经处于网络字节序。

贡献

通过参与此项目,您同意遵守贡献者行为准则

贡献者列表可在 GitHub 上获得.

许可证

This is free and unencumbered software released into the public domain. For more information, please refer to the UNLICENSE file or unlicense.org.