gpt4 book ai didi

swift - swift 的BSON?

转载 作者:可可西里 更新时间:2023-11-01 01:37:50 25 4
gpt4 key购买 nike

此时我的问题很开放,但我很好奇是否有人在 Swift 中为 BSON 实现了类似 SwiftyJSON 的东西?

我发现 Perfect project 有一些东西,但它似乎只是一个现有 C 库的包装器(在 iOS 方面对我没有任何好处)。我只是玩弄了 SwiftyJSON 的移植/变形,到目前为止,它的内部结构略高于我的学习曲线,而且它似乎只是平台的 JSONSerialization 的包装器。

谁也一样

A) 知道我的谷歌搜索还没有发现的事情,或者

B) 或者可以帮助我在正确的方向上插入我如何总体架构这样的东西? (不是试图让别人为我工作)

旁白:为了避免“你为什么不直接使用 json”的问题...这是因为我在另一边做了相当多的 MongoDB,而且我使用了很多字符串和日期,必须在 JSON 中模糊表示

最佳答案

为了结束......我最终写了自己的。它不是针对所有 BSON 编码的完整解决方案,只是我正在使用的编码。弄清楚如何使用 Swift 枚举来做到这一点很有趣。

import Foundation

extension GeneratorType {
mutating func next(n: Int) -> [Element] {
var result: [Element] = []
for _ in 1...n {
if let next = self.next() {
result.append(next)
} else {
break
}
}
return result
}
}

extension GeneratorType where Element:Comparable {
mutating func upTo(match:Element) -> [Element]? {
var result: [Element] = []
while let next = self.next() {
if next == match {
return result
}
else {
result.append(next)
}
}
return nil
}
}

extension String {
init?<S : SequenceType, C : UnicodeCodecType where S.Generator.Element == C.CodeUnit>
(codeUnits : S, inout codec : C) {
var str = ""
var generator = codeUnits.generate()
var done = false
while !done {
let r = codec.decode(&generator)
switch (r) {
case .EmptyInput:
done = true
case let .Result(val):
str.append(Character(val))
case .Error:
return nil
}
}
self = str
}
}

enum BSON {
static func toByteArray<T>(value: T) -> [UInt8] {
var io = value
return withUnsafePointer(&io) {
Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>($0), count: sizeof(T)))
}
}

static func fromByteArray<T>(value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}

struct Field {
var name:String
var element:BSON
}

case double(Double)
case string(String)
case document([Field])
case array([BSON])
case binary([UInt8])
// case objectid((UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8))
case boolean(Bool)
case datetime(NSDate)
case null
case int32(Int32)
case int64(Int64)

init() {
self = .document([])
}

var bsonType:UInt8 {
switch self {
case .double: return 0x01
case .string: return 0x02
case .document: return 0x03
case .array: return 0x04
case .binary: return 0x05
// case .objectid: return 0x07
case .boolean: return 0x08
case .datetime: return 0x09
case .null: return 0x0A
case .int32: return 0x10
case .int64: return 0x12
}
}

subscript(key:String) -> BSON {
get {
switch self {
case .document (let fields):
for field in fields {
if field.name == key {
return field.element
}
}
return BSON.null
default:
return BSON.null
}
}
set(newValue) {
var newFields:[Field] = []
switch self {
case .document (let fields):
newFields = fields
var append = true
for (index, field) in newFields.enumerate() {
if field.name == key {
newFields[index].element = newValue
append = false
break
}
}
if append {
newFields.append(Field(name: key, element: newValue))
}
default:
newFields = [Field(name: key, element: newValue)]
}
self = .document(newFields)
}
}


subscript(index:Int) -> BSON {
get {
switch self {
case .array (let elements):
return index < elements.count ? elements[index] : BSON.null
default:
return BSON.null
}
}
set(newValue) {
switch self {
case .array (let elements):
if index < elements.count {
var newElements = elements
newElements[index] = newValue
self = .array(newElements)
}
default:
break
}
}
}

func encoded() -> [UInt8] {
switch self {
case double (let value):
return BSON.toByteArray(value)
case string (let value):
let encoded = value.utf8
return BSON.toByteArray(Int32(encoded.count + 1)) + encoded + [0]
case document (let fields):
var body:[UInt8] = []
for field in fields ?? [] {
body += [field.element.bsonType]
body += field.name.utf8
body += [0]
body += field.element.encoded()
}
body += [0]
return BSON.toByteArray(Int32(body.count + 4)) + body
case array (let elements):
var body:[UInt8] = []
for (index, element) in elements.enumerate() {
body += [element.bsonType]
body += String(index).utf8
body += [0]
body += element.encoded()
}
body += [0]
return BSON.toByteArray(Int32(body.count + 4)) + body
case binary (let bytes):
return BSON.toByteArray(Int32(bytes.count)) + [0x00] + bytes
// case objectid:
// return []
case boolean (let value):
return value ? [0x01] : [0x00]
case datetime (let value):
let since = Int64(value.timeIntervalSince1970 * 1000.0)
return BSON.toByteArray(since)
case null:
return []
case int32 (let value):
return BSON.toByteArray(value)
case int64 (let value):
return BSON.toByteArray(value)
}
}

static func decode(inout stream stream:IndexingGenerator<[UInt8]>, bsonType:UInt8 = 0x03) -> BSON {
switch bsonType {
case 0x01:
let bytes = stream.next(sizeof(Double))
return self.double(fromByteArray(bytes, Double.self))
case 0x02:
let _ = stream.next(sizeof(Int32)) // skip the count
if let buffer = stream.upTo(0) {
var codec = UTF8()
if let decoded = String(codeUnits: buffer, codec: &codec) {
return self.string(decoded)
}
}
fatalError("utf8 parse error!")
case 0x03:
var fields:[Field] = []
stream.next(sizeof(Int32)) // throw out size
while let bsonType = stream.next() {
if bsonType == 0 {
return self.document(fields)
}
if let buffer = stream.upTo(0) {
var codec = UTF8()
if let fieldName = String(codeUnits: buffer, codec: &codec) {
let element = BSON.decode(stream:&stream, bsonType: bsonType)
fields.append(Field(name: fieldName, element: element))
}
}
}
case 0x04:
var elements:[BSON] = []
stream.next(sizeof(Int32)) // throw out size
while let bsonType = stream.next() {
if bsonType == 0 {
return self.array(elements)
}
stream.upTo(0) // skip name
elements.append(BSON.decode(stream:&stream, bsonType: bsonType))
}
case 0x05:
let count = fromByteArray(stream.next(sizeof(Int32)), Int32.self)
assert(stream.next() == 0x00)
return self.binary(stream.next(Int(count)))
case 0x07:
break
case 0x08:
let value = stream.next()
return self.boolean(value == 0x01)
case 0x09:
let milliseconds = fromByteArray(stream.next(sizeof(Int64)), Int64.self)
let interval = NSTimeInterval(milliseconds) / 1000.0
return self.datetime(NSDate(timeIntervalSince1970: interval))
case 0x0A:
return self.null
case 0x10:
let value = fromByteArray(stream.next(sizeof(Int32)), Int32.self)
return self.int32(value)
case 0x12:
let value = fromByteArray(stream.next(sizeof(Int64)), Int64.self)
return self.int64(value)
default:
break
}
fatalError()
}

var document:BSON? {
switch self {
case .document:
return self
default:
return nil
}
}

var double:Double? {
switch self {
case .double (let value):
return value
default:
return nil
}
}

var int32:Int32? {
get {
switch self {
case .int32 (let value):
return value
default:
return nil
}
}
set {
if let newValue = newValue {
self = .int32(newValue)
}
else {
self = .null
}
}
}


var int64:Int64? {
switch self {
case .int64 (let value):
return value
default:
return nil
}
}

var boolean:Bool? {
switch self {
case .boolean (let value):
return value
default:
return nil
}
}

var binary:[UInt8]? {
switch self {
case .binary (let value):
return value
default:
return nil
}
}

var string:String? {
switch self {
case .string (let value):
return value
default:
return nil
}
}

var datetime:NSDate? {
switch self {
case .datetime (let value):
return value
default:
return nil
}
}

var array:[BSON]? {
switch self {
case .array (let elements):
return elements
default:
return nil
}
}

var isNull:Bool {
switch self {
case .null:
return true
default:
return false
}
}

var keyValues:[(String, BSON)] {
switch self {
case document (let fields):
return fields.map() { ($0.name, $0.element) }
default:
return []
}
}

}

extension BSON: Equatable {}
extension BSON.Field: Equatable {}

func == (a:BSON.Field, b:BSON.Field) -> Bool {
return a.name == b.name && a.element == b.element
}

func == (a:BSON, b:BSON) -> Bool {
switch (a, b) {
case (.double(let a), .double(let b)) where a == b: return true
case (.string(let a), .string(let b)) where a == b: return true
case (.document(let a), .document(let b)) where a == b: return true
case (.array(let a), .array(let b)) where a == b: return true
case (.binary(let a), .binary(let b)) where a == b: return true
case (.boolean(let a), .boolean(let b)) where a == b: return true
case (.datetime(let a), .datetime(let b)) where a.isEqualToDate(b): return true
case (.null, .null): return true
case (.int32(let a), .int32(let b)) where a == b: return true
case (.int64(let a), .int64(let b)) where a == b: return true
default: return false
}
}

protocol BSONConvertable {
var bson:BSON { get }
}

extension Int32: BSONConvertable {
var bson:BSON {
return BSON.int32(self)
}
}

extension Int64: BSONConvertable {
var bson:BSON {
return BSON.int64(self)
}
}

extension Int: BSONConvertable {
var bson:BSON {
let wide = self.toIntMax()
if Int32.min.toIntMax() <= wide && wide <= Int32.max.toIntMax() {
return BSON.int32(Int32(wide))
}
else {
return BSON.int64(Int64(wide))
}
}
}


extension Float:BSONConvertable {
var bson:BSON {
return Double(self).bson
}
}

extension Double:BSONConvertable {
var bson:BSON {
return BSON.double(self)
}
}

extension Bool:BSONConvertable {
var bson:BSON {
return BSON.boolean(self)
}
}

extension BSON:BSONConvertable {
var bson:BSON {
return self
}
}

extension NSDate:BSONConvertable {
var bson:BSON {
return BSON.datetime(self)
}
}

extension String:BSONConvertable {
var bson:BSON {
return BSON.string(self)
}
}

extension Array where Element:BSONConvertable {
var bson:BSON {
return BSON.array(self.map({$0.bson}))
}
}

关于swift - swift 的BSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34074538/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com