blob: 74635dbc8959d46e09636f896abef5c3059a7219 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Note: Imported C structs have a default initializer in Swift that zero-initializes all fields.
// https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html
import Foundation
public extension v23_syncbase_AppPeer {
func toNeighborhoodPeer() -> NeighborhoodPeer {
return NeighborhoodPeer(
appName: appName.toString() ?? "",
blessings: blessings.toString() ?? "",
isLost: isLost)
}
}
public extension v23_syncbase_BatchOptions {
init (_ opts: BatchOptions?) throws {
guard let o = opts else {
self.hint = v23_syncbase_String()
self.readOnly = false
return
}
self.hint = try o.hint?.toCgoString() ?? v23_syncbase_String()
self.readOnly = o.readOnly
}
}
public extension v23_syncbase_Bytes {
init(_ data: NSData?) {
guard let data = data else {
self.n = 0
self.p = nil
return
}
let p = malloc(data.length)
if p == nil {
fatalError("Couldn't allocate \(data.length) bytes")
}
let n = data.length
data.getBytes(p, length: n)
self.p = UnsafeMutablePointer<UInt8>(p)
self.n = Int32(n)
}
// Return value takes ownership of the memory associated with this object.
func toNSData() -> NSData? {
if p == nil {
return nil
}
return NSData(bytesNoCopy: UnsafeMutablePointer<Void>(p), length: Int(n), freeWhenDone: true)
}
}
public extension v23_syncbase_ChangeType {
func toChangeType() -> WatchChange.ChangeType? {
return WatchChange.ChangeType(rawValue: Int(self.rawValue))
}
}
public extension v23_syncbase_CollectionRowPattern {
init(_ pattern: CollectionRowPattern) throws {
self.collectionBlessing = try pattern.collectionBlessing.toCgoString()
self.collectionName = try pattern.collectionName.toCgoString()
self.rowKey = try (pattern.rowKey ?? "").toCgoString()
}
}
public extension v23_syncbase_CollectionRowPatterns {
init(_ patterns: [CollectionRowPattern]) throws {
if (patterns.isEmpty) {
self.n = 0
self.p = nil
return
}
let numBytes = patterns.count * sizeof(v23_syncbase_CollectionRowPattern)
self.p = unsafeBitCast(malloc(numBytes), UnsafeMutablePointer<v23_syncbase_CollectionRowPattern>.self)
if self.p == nil {
fatalError("Couldn't allocate \(numBytes) bytes")
}
self.n = Int32(patterns.count)
var i = 0
do {
for pattern in patterns {
self.p.advancedBy(i).memory = try v23_syncbase_CollectionRowPattern(pattern)
i += 1
}
} catch let e {
free(self.p)
self.p = nil
self.n = 0
throw e
}
}
}
public extension v23_syncbase_EntityType {
func toEntityType() -> WatchChange.EntityType? {
return WatchChange.EntityType(rawValue: Int(self.rawValue))
}
}
public extension v23_syncbase_Id {
init(_ id: Identifier) throws {
self.name = try id.name.toCgoString()
self.blessing = try id.blessing.toCgoString()
}
func toIdentifier() -> Identifier? {
guard let name = name.toString(),
blessing = blessing.toString() else {
return nil
}
return Identifier(name: name, blessing: blessing)
}
}
public extension v23_syncbase_Ids {
init(_ ids: [Identifier]) throws {
let arrayBytes = ids.count * sizeof(v23_syncbase_Id)
let p = unsafeBitCast(malloc(arrayBytes), UnsafeMutablePointer<v23_syncbase_Id>.self)
if p == nil {
fatalError("Couldn't allocate \(arrayBytes) bytes")
}
for i in 0 ..< ids.count {
do {
p.advancedBy(i).memory = try v23_syncbase_Id(ids[i])
} catch (let e) {
for j in 0 ..< i {
free(p.advancedBy(j).memory.blessing.p)
free(p.advancedBy(j).memory.name.p)
}
free(p)
throw e
}
}
self.p = p
self.n = Int32(ids.count)
}
func toIdentifiers() -> [Identifier] {
var ids: [Identifier] = []
for i in 0 ..< n {
let idStruct = p.advancedBy(Int(i)).memory
if let id = idStruct.toIdentifier() {
ids.append(id)
}
}
if p != nil {
free(p)
}
return ids
}
}
public extension v23_syncbase_Invite {
func toSyncgroupInvite() -> SyncgroupInvite? {
guard let id = syncgroup.toIdentifier() else {
return nil
}
return SyncgroupInvite(
syncgroupId: id,
addresses: addresses.toStrings(),
blessingNames: blessingNames.toStrings())
}
}
public extension v23_syncbase_Permissions {
init(_ permissions: Permissions?) throws {
guard let p = permissions where !p.isEmpty else {
// Zero-value constructor.
self.json = v23_syncbase_Bytes()
return
}
var m = [String: AnyObject]()
for (key, value) in p {
m[key as String] = (value as AccessList).toJsonable()
}
let serialized = try NSJSONSerialization.serialize(m)
let bytes = v23_syncbase_Bytes(serialized)
self.json = bytes
}
func toPermissions() throws -> Permissions? {
guard let data = self.json.toNSData(),
map = try NSJSONSerialization.deserialize(data) as? NSDictionary else {
return nil
}
var p = Permissions()
for (k, v) in map {
guard let key = k as? String,
jsonAcessList = v as? [String: AnyObject] else {
throw SyncbaseError.CastError(obj: v)
}
p[key] = AccessList.fromJsonable(jsonAcessList)
}
return p
}
}
public extension v23_syncbase_String {
init(_ string: String) throws {
// TODO: If possible, make one copy instead of two, e.g. using s.getCString.
guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else {
throw SyncbaseError.InvalidUTF8(invalidUtf8: string)
}
let p = malloc(data.length)
if p == nil {
fatalError("Unable to allocate \(data.length) bytes")
}
let n = data.length
data.getBytes(p, length: n)
self.p = UnsafeMutablePointer<Int8>(p)
self.n = Int32(n)
}
// Return value takes ownership of the memory associated with this object.
func toString() -> String? {
if p == nil {
return nil
}
return String(bytesNoCopy: UnsafeMutablePointer<Void>(p),
length: Int(n),
encoding: NSUTF8StringEncoding,
freeWhenDone: true)
}
}
public extension v23_syncbase_Strings {
init(_ strings: [String]) throws {
let arrayBytes = strings.count * sizeof(v23_syncbase_String)
let p = unsafeBitCast(malloc(arrayBytes), UnsafeMutablePointer<v23_syncbase_String>.self)
if p == nil {
fatalError("Couldn't allocate \(arrayBytes) bytes")
}
for i in 0 ..< strings.count {
do {
p.advancedBy(i).memory = try v23_syncbase_String(strings[i])
} catch (let e) {
for j in 0 ..< i {
free(p.advancedBy(j).memory.p)
}
free(p)
throw e
}
}
self.p = p
self.n = Int32(strings.count)
}
init(_ strings: [v23_syncbase_String]) {
let arrayBytes = strings.count * sizeof(v23_syncbase_String)
let p = unsafeBitCast(malloc(arrayBytes), UnsafeMutablePointer<v23_syncbase_String>.self)
if p == nil {
fatalError("Couldn't allocate \(arrayBytes) bytes")
}
var i = 0
for string in strings {
p.advancedBy(i).memory = string
i += 1
}
self.p = p
self.n = Int32(strings.count)
}
// Return value takes ownership of the memory associated with this object.
func toStrings() -> [String] {
if p == nil {
return []
}
var ret = [String]()
for i in 0 ..< n {
ret.append(p.advancedBy(Int(i)).memory.toString() ?? "")
}
free(p)
return ret
}
}
public extension String {
/// Create a Cgo-passable string struct forceably (will crash if the string cannot be created).
func toCgoString() throws -> v23_syncbase_String {
return try v23_syncbase_String(self)
}
}
public extension v23_syncbase_SyncgroupMemberInfo {
init(_ info: SyncgroupMemberInfo) {
self.syncPriority = info.syncPriority
self.blobDevType = UInt8(info.blobDevType.rawValue)
}
func toSyncgroupMemberInfo() -> SyncgroupMemberInfo {
return SyncgroupMemberInfo(
syncPriority: syncPriority,
blobDevType: BlobDevType(rawValue: Int(blobDevType))!)
}
}
public extension v23_syncbase_SyncgroupMemberInfoMap {
func toSyncgroupMemberInfoMap() -> [String: SyncgroupMemberInfo] {
var ret = [String: SyncgroupMemberInfo]()
for i in 0 ..< Int(n) {
let key = keys.advancedBy(i).memory.toString() ?? ""
let value = values.advancedBy(i).memory.toSyncgroupMemberInfo()
ret[key] = value
}
free(keys)
free(values)
return ret
}
}
public extension v23_syncbase_SyncgroupSpec {
init(_ spec: SyncgroupSpec) throws {
self.collections = try v23_syncbase_Ids(spec.collections)
self.description = try spec.description.toCgoString()
self.isPrivate = spec.isPrivate
self.mountTables = try v23_syncbase_Strings(spec.mountTables)
self.perms = try v23_syncbase_Permissions(spec.permissions)
self.publishSyncbaseName = try spec.publishSyncbaseName?.toCgoString() ?? v23_syncbase_String()
}
func toSyncgroupSpec() throws -> SyncgroupSpec {
return SyncgroupSpec(
description: self.description.toString() ?? "",
collections: self.collections.toIdentifiers(),
permissions: try self.perms.toPermissions() ?? [:],
publishSyncbaseName: self.publishSyncbaseName.toString(),
mountTables: self.mountTables.toStrings(),
isPrivate: self.isPrivate)
}
}
public extension v23_syncbase_WatchChange {
func toWatchChange() -> WatchChange {
let resumeMarkerData = v23_syncbase_Bytes(
p: unsafeBitCast(self.resumeMarker.p, UnsafeMutablePointer<UInt8>.self),
n: self.resumeMarker.n).toNSData()
// Turn row & collectionId zero-values into nil.
var row = self.row.toString()
if row == "" {
row = nil
}
var collectionId = self.collection.toIdentifier()
if collectionId?.name == "" && collectionId?.blessing == "" {
collectionId = nil
}
// Zero-valued Value does not get turned into a nil on put -- if it's a put then we know
// it cannot be nil. This allows us to store empty arrays (an esoteric use case but one that
// is supported nevertheless).
var value = self.value.toNSData()
if value == nil && self.changeType == v23_syncbase_ChangeTypePut {
value = NSData()
}
return WatchChange(
entityType: self.entityType.toEntityType()!,
collectionId: collectionId,
row: row,
changeType: self.changeType.toChangeType()!,
value: value,
resumeMarker: resumeMarkerData,
isFromSync: self.fromSync,
isContinued: self.continued)
}
}
// Note, we don't define init(VError) since we never pass Swift VError objects to Go.
public extension v23_syncbase_VError {
// Return value takes ownership of the memory associated with this object.
func toVError() -> VError? {
if id.p == nil {
return nil
}
// Take ownership of all memory before checking optionals.
let vId = id.toString(), vMsg = msg.toString(), vStack = stack.toString()
// TODO: Stop requiring id, msg, and stack to be valid UTF-8?
return VError(id: vId!, actionCode: actionCode, msg: vMsg ?? "", stack: vStack!)
}
}
public struct VError: ErrorType {
public let id: String
public let actionCode: UInt32
public let msg: String
public let stack: String
static func maybeThrow<T>(@noescape f: UnsafeMutablePointer<v23_syncbase_VError> throws -> T) throws -> T {
var e = v23_syncbase_VError()
let res = try f(&e)
if let err = e.toVError() {
throw SyncbaseError(err)
}
return res
}
}