SwiftCBOR
Swift 的一个 RBOR (RFC 7049 简洁二进制对象表示) 解码器和编码器。可以直 接从 Swift 类型编码,或使用包装对象。解码到可以像原生 Swift 下标一样访问并使用等效字面符号表 达的 CBOR 值类型。
- 一个全平台的 Swift 5.x 包!
Codable
支持!- 负整数以
NegativeInt(UInt)
解码,其中实际数字为-1 - i
(CBOR 的负整数可能会超过 64 位有符号整数)。 - 会解码标签,但不处理。标签值编码,但不类型检查。自己做吧 :)
- 为
CBOR
类型定义了字面量可转换。 - 以及
下标
。所以您可以像这样访问 CBOR 映射和数组:myDecodedObject["numbers"][1]
。 - 如果您要从流解码,请在实际流上实现
CBORInputStream
协议,并创建解码器,如下所示:CBORDecoder(stream: yourStream)
。 - 半精度浮点数可以解码成 Float,可能甚至会正确。不支持编码 Float16(Swift 中不存在)。
- 编码的内存效率需要调整。(通常编码不就地执行。)
- 支持编码不定长数据,但您需要显式地将打开和关闭信息添加到您的流数据中。
- 建议使用 cbor.me 来查看您的 CBOR 编码数据。
安装
有多种方式:Swift 包管理器、CocoaPods、git 子模块...
CocoaPod 是由贡献者提交的,那里可能有延迟更新。
Swift 包管理器是推荐的依赖项管理器。
解码
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映射。您可以为会构建CBOR
值并对其进行编码的您的类型实现CBOREncodable
,或者不使用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]
。查看编码器函数以获取灵感。
编码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]
不定长度数据
为了对不定长数组、映射、字符串和字节字符串进行编码,请显式使用开放和关闭流的CBOR值。在这两个值之间,使用编码后的数组和映射块,通过CBOR.encodeArrayChunk
和CBOR.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
为true,则除 UInt8类型外的所有类型的数组将反转每个项目的原始字节(但不会改变项目顺序),如果计算机是小端字节序(CBOR使用大端或网络字节序)。UInt8数组被认为是已经处于网络字节序。
贡献
通过参与此项目,您同意遵守贡献者行为规范。
许可证
这是免费且无负担的软件,已发布到公共领域。更多信息,请参阅代码UNLICENSE
文件或unlicense.org。