cloudkit 0.1.0

Safe Rust bindings for Apple's CloudKit framework — iCloud databases and sync on macOS
Documentation
import CloudKit
import Foundation

@_cdecl("ck_record_create")
public func ckRecordCreate(
    _ recordType: UnsafePointer<CChar>?,
    _ outJSON: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
    _ outErrorJSON: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Int32 {
    do {
        guard let recordType else {
            throw ckBridgeNSError(code: CKR_INVALID_ARGUMENT, message: "Missing record type")
        }
        let record = CKRecord(recordType: String(cString: recordType))
        let payload = try ckEncodeRecord(record)
        outJSON?.pointee = ckCString(try ckEncodeJSON(payload))
        return CKR_OK
    } catch let error as NSError {
        ckWriteError(error, to: outErrorJSON)
        return Int32(error.code)
    }
}

@_cdecl("ck_container_account_status_sync")
public func ckContainerAccountStatusSync(
    _ containerIdentifier: UnsafePointer<CChar>?,
    _ outStatus: UnsafeMutablePointer<Int32>?,
    _ outErrorJSON: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Int32 {
    do {
        let container = try ckMakeContainer(containerIdentifier)
        let status = try ckAwait(label: "CloudKit account status") { completion in
            container.accountStatus { status, error in
                completion(status, error as NSError?)
            }
        }
        outStatus?.pointee = Int32(status.rawValue)
        return CKR_OK
    } catch let error as NSError {
        ckWriteError(error, to: outErrorJSON)
        return Int32(error.code)
    }
}

@_cdecl("ck_container_account_status_async")
public func ckContainerAccountStatusAsync(
    _ containerIdentifier: UnsafePointer<CChar>?,
    _ callback: @escaping CKAccountStatusCallback,
    _ refcon: UnsafeMutableRawPointer?
) {
    let boxPtr = ckRetain(CKAccountStatusCallbackBox(callback: callback, refcon: refcon))
    do {
        let container = try ckMakeContainer(containerIdentifier)
        container.accountStatus { status, error in
            let box: CKAccountStatusCallbackBox = ckUnretained(boxPtr, as: CKAccountStatusCallbackBox.self)
            box.complete(status: status, error: error as NSError?)
            ckRelease(boxPtr)
        }
    } catch let error as NSError {
        let box: CKAccountStatusCallbackBox = ckUnretained(boxPtr, as: CKAccountStatusCallbackBox.self)
        box.complete(status: .couldNotDetermine, error: error)
        ckRelease(boxPtr)
    }
}

@_cdecl("ck_container_fetch_user_record_id_sync")
public func ckContainerFetchUserRecordIDSync(
    _ containerIdentifier: UnsafePointer<CChar>?,
    _ outJSON: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
    _ outErrorJSON: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Int32 {
    do {
        let container = try ckMakeContainer(containerIdentifier)
        let recordID = try ckAwait(label: "CloudKit user record ID") { completion in
            container.fetchUserRecordID { recordID, error in
                completion(recordID, error as NSError?)
            }
        }
        outJSON?.pointee = ckCString(try ckEncodeJSON(ckEncodeRecordID(recordID)))
        return CKR_OK
    } catch let error as NSError {
        ckWriteError(error, to: outErrorJSON)
        return Int32(error.code)
    }
}

@_cdecl("ck_container_fetch_user_record_id_async")
public func ckContainerFetchUserRecordIDAsync(
    _ containerIdentifier: UnsafePointer<CChar>?,
    _ callback: @escaping CKJSONStringCallback,
    _ refcon: UnsafeMutableRawPointer?
) {
    let boxPtr = ckRetain(CKJSONStringCallbackBox(callback: callback, refcon: refcon))
    do {
        let container = try ckMakeContainer(containerIdentifier)
        container.fetchUserRecordID { recordID, error in
            let box: CKJSONStringCallbackBox = ckUnretained(boxPtr, as: CKJSONStringCallbackBox.self)
            if let error = error as NSError? {
                box.fail(error: error)
            } else if let recordID {
                let json = (try? ckEncodeJSON(ckEncodeRecordID(recordID))) ?? "{}"
                box.succeed(json: json)
            } else {
                box.fail(error: ckBridgeNSError(code: CKR_FAILURE, message: "CloudKit returned a nil user record ID"))
            }
            ckRelease(boxPtr)
        }
    } catch let error as NSError {
        let box: CKJSONStringCallbackBox = ckUnretained(boxPtr, as: CKJSONStringCallbackBox.self)
        box.fail(error: error)
        ckRelease(boxPtr)
    }
}