Skip to content

Commit 05e5e41

Browse files
committed
Xcode 7 beta 6: Use C Function Pointer API
Signed-off-by: Stephen Celis <stephen@stephencelis.com>
1 parent dc1a88a commit 05e5e41

File tree

3 files changed

+95
-152
lines changed

3 files changed

+95
-152
lines changed

Source/Core/Connection.swift

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -357,31 +357,43 @@ public final class Connection {
357357
/// times it’s been called for this lock. If it returns `true`, it will
358358
/// try again. If it returns `false`, no further attempts will be made.
359359
public func busyHandler(callback: ((tries: Int) -> Bool)?) {
360-
if let callback = callback {
361-
busyHandler = { callback(tries: Int($0)) ? 1 : 0 }
362-
} else {
360+
guard let callback = callback else {
361+
sqlite3_busy_handler(handle, nil, nil)
363362
busyHandler = nil
363+
return
364364
}
365+
366+
let box: BusyHandler = { callback(tries: Int($0)) ? 1 : 0 }
367+
sqlite3_busy_handler(handle, { callback, tries in
368+
unsafeBitCast(callback, BusyHandler.self)(tries)
369+
}, unsafeBitCast(box, UnsafeMutablePointer<Void>.self))
370+
busyHandler = box
365371
}
366-
private var busyHandler: _SQLiteBusyHandlerCallback?
372+
private typealias BusyHandler = @convention(block) Int32 -> Int32
373+
private var busyHandler: BusyHandler?
367374

368375
/// Sets a handler to call when a statement is executed with the compiled
369376
/// SQL.
370377
///
371378
/// - Parameter callback: This block is invoked when a statement is executed
372-
/// with the compiled SQL as its argument. E.g., pass `print` to act as a
373-
/// logger.
379+
/// with the compiled SQL as its argument.
374380
///
375-
/// db.trace(print)
381+
/// db.trace { SQL in print(SQL) }
376382
public func trace(callback: (String -> Void)?) {
377-
if let callback = callback {
378-
trace = { callback(String.fromCString($0)!) }
379-
} else {
383+
guard let callback = callback else {
384+
sqlite3_trace(handle, nil, nil)
380385
trace = nil
386+
return
381387
}
382-
_SQLiteTrace(handle, trace)
388+
389+
let box: Trace = { callback(String.fromCString($0)!) }
390+
sqlite3_trace(handle, { callback, SQL in
391+
unsafeBitCast(callback, Trace.self)(SQL)
392+
}, unsafeBitCast(box, UnsafeMutablePointer<Void>.self))
393+
trace = box
383394
}
384-
private var trace: _SQLiteTraceCallback?
395+
private typealias Trace = @convention(block) UnsafePointer<Int8> -> Void
396+
private var trace: Trace?
385397

386398
/// Registers a callback to be invoked whenever a row is inserted, updated,
387399
/// or deleted in a rowid table.
@@ -390,53 +402,75 @@ public final class Connection {
390402
/// `.Insert`, `.Update`, or `.Delete`), database name, table name, and
391403
/// rowid.
392404
public func updateHook(callback: ((operation: Operation, db: String, table: String, rowid: Int64) -> Void)?) {
393-
if let callback = callback {
394-
updateHook = { operation, db, table, rowid in
395-
callback(
396-
operation: Operation(rawValue: operation),
397-
db: String.fromCString(db)!,
398-
table: String.fromCString(table)!,
399-
rowid: rowid
400-
)
401-
}
402-
} else {
405+
guard let callback = callback else {
406+
sqlite3_update_hook(handle, nil, nil)
403407
updateHook = nil
408+
return
404409
}
405-
_SQLiteUpdateHook(handle, updateHook)
410+
411+
let box: UpdateHook = {
412+
callback(
413+
operation: Operation(rawValue: $0),
414+
db: String.fromCString($1)!,
415+
table: String.fromCString($2)!,
416+
rowid: $3
417+
)
418+
}
419+
sqlite3_update_hook(handle, { callback, operation, db, table, rowid in
420+
unsafeBitCast(callback, UpdateHook.self)(operation, db, table, rowid)
421+
}, unsafeBitCast(box, UnsafeMutablePointer<Void>.self))
422+
updateHook = box
406423
}
407-
private var updateHook: _SQLiteUpdateHookCallback?
424+
private typealias UpdateHook = @convention(block) (Int32, UnsafePointer<Int8>, UnsafePointer<Int8>, Int64) -> Void
425+
private var updateHook: UpdateHook?
408426

409427
/// Registers a callback to be invoked whenever a transaction is committed.
410428
///
411429
/// - Parameter callback: A callback invoked whenever a transaction is
412430
/// committed. If this callback throws, the transaction will be rolled
413431
/// back.
414432
public func commitHook(callback: (() throws -> Void)?) {
415-
if let callback = callback {
416-
commitHook = {
417-
do {
418-
try callback()
419-
return 0
420-
} catch {
421-
return 1
422-
}
423-
}
424-
} else {
433+
guard let callback = callback else {
434+
sqlite3_commit_hook(handle, nil, nil)
425435
commitHook = nil
436+
return
426437
}
427-
_SQLiteCommitHook(handle, commitHook)
438+
439+
let box: CommitHook = {
440+
do {
441+
try callback()
442+
} catch {
443+
return 1
444+
}
445+
return 0
446+
}
447+
sqlite3_commit_hook(handle, { callback in
448+
unsafeBitCast(callback, CommitHook.self)()
449+
}, unsafeBitCast(box, UnsafeMutablePointer<Void>.self))
450+
commitHook = box
428451
}
429-
private var commitHook: _SQLiteCommitHookCallback?
452+
private typealias CommitHook = @convention(block) () -> Int32
453+
private var commitHook: CommitHook?
430454

431455
/// Registers a callback to be invoked whenever a transaction rolls back.
432456
///
433457
/// - Parameter callback: A callback invoked when a transaction is rolled
434458
/// back.
435-
public func rollbackHook(callback: _SQLiteRollbackHookCallback?) {
436-
rollbackHook = callback
437-
_SQLiteRollbackHook(handle, rollbackHook)
459+
public func rollbackHook(callback: (() -> Void)?) {
460+
guard let callback = callback else {
461+
sqlite3_rollback_hook(handle, nil, nil)
462+
rollbackHook = nil
463+
return
464+
}
465+
466+
let box: RollbackHook = { callback() }
467+
sqlite3_rollback_hook(handle, { callback in
468+
unsafeBitCast(callback, RollbackHook.self)()
469+
}, unsafeBitCast(box, UnsafeMutablePointer<Void>.self))
470+
rollbackHook = box
438471
}
439-
private var rollbackHook: _SQLiteRollbackHookCallback?
472+
private typealias RollbackHook = @convention(block) () -> Void
473+
private var rollbackHook: RollbackHook?
440474

441475
/// Creates or redefines a custom SQL function.
442476
///
@@ -459,8 +493,7 @@ public final class Connection {
459493
/// parameters and should return a raw SQL value (or nil).
460494
public func createFunction(function: String, argumentCount: UInt? = nil, deterministic: Bool = false, _ block: (args: [Binding?]) -> Binding?) {
461495
let argc = argumentCount.map { Int($0) } ?? -1
462-
if functions[function] == nil { self.functions[function] = [:] }
463-
functions[function]?[argc] = { context, argc, argv in
496+
let box: Function = { context, argc, argv in
464497
let arguments: [Binding?] = (0..<Int(argc)).map { idx in
465498
let value = argv[idx]
466499
switch sqlite3_value_type(value) {
@@ -493,10 +526,18 @@ public final class Connection {
493526
fatalError("unsupported result type: \(result)")
494527
}
495528
}
496-
try! check(_SQLiteCreateFunction(handle, function, Int32(argc), deterministic ? 1 : 0, functions[function]?[argc]))
529+
var flags = SQLITE_UTF8
530+
if deterministic {
531+
flags |= SQLITE_DETERMINISTIC
532+
}
533+
sqlite3_create_function_v2(handle, function, Int32(argc), flags, unsafeBitCast(box, UnsafeMutablePointer<Void>.self), { context, argc, value in
534+
unsafeBitCast(sqlite3_user_data(context), Function.self)(context, argc, value)
535+
}, nil, nil, nil)
536+
if functions[function] == nil { self.functions[function] = [:] }
537+
functions[function]?[argc] = box
497538
}
498-
private var functions = [String: [Int: _SQLiteCreateFunctionCallback]]()
499-
539+
private typealias Function = @convention(block) (COpaquePointer, Int32, UnsafeMutablePointer<COpaquePointer>) -> Void
540+
private var functions = [String: [Int: Function]]()
500541

501542
/// The return type of a collation comparison function.
502543
public typealias ComparisonResult = NSComparisonResult
@@ -510,12 +551,16 @@ public final class Connection {
510551
/// - block: A collation function that takes two strings and returns the
511552
/// comparison result.
512553
public func createCollation(collation: String, _ block: (lhs: String, rhs: String) -> ComparisonResult) {
513-
collations[collation] = { lhs, rhs in
514-
Int32(block(lhs: String.fromCString(lhs)!, rhs: String.fromCString(rhs)!).rawValue)
554+
let box: Collation = { lhs, rhs in
555+
Int32(block(lhs: String.fromCString(UnsafePointer<Int8>(lhs))!, rhs: String.fromCString(UnsafePointer<Int8>(rhs))!).rawValue)
515556
}
516-
try! check(_SQLiteCreateCollation(handle, collation, collations[collation]))
557+
try! check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8, unsafeBitCast(box, UnsafeMutablePointer<Void>.self), { callback, _, lhs, _, rhs in
558+
unsafeBitCast(callback, Collation.self)(lhs, rhs)
559+
}, nil))
560+
collations[collation] = box
517561
}
518-
private var collations = [String: _SQLiteCreateCollationCallback]()
562+
private typealias Collation = @convention(block) (UnsafePointer<Void>, UnsafePointer<Void>) -> Int32
563+
private var collations = [String: Collation]()
519564

520565
// MARK: - Error Handling
521566

Source/Core/SQLite-Bridging.h

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,33 +28,9 @@
2828
#import "sqlite3.h"
2929
#endif
3030

31-
// CocoaPods workaround
32-
typedef struct SQLiteHandle SQLiteHandle;
33-
typedef struct SQLiteContext SQLiteContext;
34-
typedef struct SQLiteValue SQLiteValue;
31+
typedef struct SQLiteHandle SQLiteHandle; // CocoaPods workaround
3532

3633
NS_ASSUME_NONNULL_BEGIN
37-
typedef int (^_SQLiteBusyHandlerCallback)(int times);
38-
int _SQLiteBusyHandler(SQLiteHandle * db, _SQLiteBusyHandlerCallback _Nullable callback);
39-
40-
typedef void (^_SQLiteTraceCallback)(const char * SQL);
41-
void _SQLiteTrace(SQLiteHandle * db, _SQLiteTraceCallback _Nullable callback);
42-
43-
typedef void (^_SQLiteUpdateHookCallback)(int operation, const char * db, const char * table, long long rowid);
44-
void _SQLiteUpdateHook(SQLiteHandle * db, _SQLiteUpdateHookCallback _Nullable callback);
45-
46-
typedef int (^_SQLiteCommitHookCallback)();
47-
void _SQLiteCommitHook(SQLiteHandle * db, _SQLiteCommitHookCallback _Nullable callback);
48-
49-
typedef void (^_SQLiteRollbackHookCallback)();
50-
void _SQLiteRollbackHook(SQLiteHandle * db, _SQLiteRollbackHookCallback _Nullable callback);
51-
52-
typedef void (^_SQLiteCreateFunctionCallback)(SQLiteContext * context, int argc, SQLiteValue * _Nonnull * _Nonnull argv);
53-
int _SQLiteCreateFunction(SQLiteHandle * db, const char * name, int argc, int deterministic, _SQLiteCreateFunctionCallback _Nullable callback);
54-
55-
typedef int (^_SQLiteCreateCollationCallback)(const char * lhs, const char * rhs);
56-
int _SQLiteCreateCollation(SQLiteHandle * db, const char * name, _SQLiteCreateCollationCallback _Nullable callback);
57-
5834
typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char * input, int * inputOffset, int * inputLength);
5935
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * module, const char * tokenizer, _Nullable _SQLiteTokenizerNextCallback callback);
6036
NS_ASSUME_NONNULL_END

Source/Core/SQLite-Bridging.m

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -30,84 +30,6 @@
3030

3131
#import "fts3_tokenizer.h"
3232

33-
static int __SQLiteBusyHandler(void * context, int tries) {
34-
return ((__bridge _SQLiteBusyHandlerCallback)context)(tries);
35-
}
36-
37-
int _SQLiteBusyHandler(SQLiteHandle * db, _SQLiteBusyHandlerCallback callback) {
38-
if (callback) {
39-
return sqlite3_busy_handler((sqlite3 *)db, __SQLiteBusyHandler, (__bridge void *)callback);
40-
} else {
41-
return sqlite3_busy_handler((sqlite3 *)db, 0, 0);
42-
}
43-
}
44-
45-
static void __SQLiteTrace(void * context, const char * SQL) {
46-
((__bridge _SQLiteTraceCallback)context)(SQL);
47-
}
48-
49-
void _SQLiteTrace(SQLiteHandle * db, _SQLiteTraceCallback callback) {
50-
if (callback) {
51-
sqlite3_trace((sqlite3 *)db, __SQLiteTrace, (__bridge void *)callback);
52-
} else {
53-
sqlite3_trace((sqlite3 *)db, 0, 0);
54-
}
55-
}
56-
57-
static void __SQLiteUpdateHook(void * context, int operation, const char * db, const char * table, long long rowid) {
58-
((__bridge _SQLiteUpdateHookCallback)context)(operation, db, table, rowid);
59-
}
60-
61-
void _SQLiteUpdateHook(SQLiteHandle * db, _SQLiteUpdateHookCallback callback) {
62-
sqlite3_update_hook((sqlite3 *)db, __SQLiteUpdateHook, (__bridge void *)callback);
63-
}
64-
65-
static int __SQLiteCommitHook(void * context) {
66-
return ((__bridge _SQLiteCommitHookCallback)context)();
67-
}
68-
69-
void _SQLiteCommitHook(SQLiteHandle * db, _SQLiteCommitHookCallback callback) {
70-
sqlite3_commit_hook((sqlite3 *)db, __SQLiteCommitHook, (__bridge void *)callback);
71-
}
72-
73-
static void __SQLiteRollbackHook(void * context) {
74-
((__bridge void (^ _Null_unspecified )())context)();
75-
}
76-
77-
void _SQLiteRollbackHook(SQLiteHandle * db, _SQLiteRollbackHookCallback _Nullable callback) {
78-
sqlite3_rollback_hook((sqlite3 *)db, __SQLiteRollbackHook, (__bridge void *)callback);
79-
}
80-
81-
static void __SQLiteCreateFunction(sqlite3_context * context, int argc, sqlite3_value ** argv) {
82-
((__bridge _SQLiteCreateFunctionCallback)sqlite3_user_data(context))((SQLiteContext *)context, argc, (SQLiteValue **)argv);
83-
}
84-
85-
int _SQLiteCreateFunction(SQLiteHandle * db, const char * name, int argc, int deterministic, _SQLiteCreateFunctionCallback callback) {
86-
if (callback) {
87-
int flags = SQLITE_UTF8;
88-
if (deterministic) {
89-
#ifdef SQLITE_DETERMINISTIC
90-
flags |= SQLITE_DETERMINISTIC;
91-
#endif
92-
}
93-
return sqlite3_create_function_v2((sqlite3 *)db, name, -1, flags, (__bridge void *)callback, &__SQLiteCreateFunction, 0, 0, 0);
94-
} else {
95-
return sqlite3_create_function_v2((sqlite3 *)db, name, 0, 0, 0, 0, 0, 0, 0);
96-
}
97-
}
98-
99-
static int __SQLiteCreateCollation(void * context, int len_lhs, const void * lhs, int len_rhs, const void * rhs) {
100-
return ((__bridge _SQLiteCreateCollationCallback)context)(lhs, rhs);
101-
}
102-
103-
int _SQLiteCreateCollation(SQLiteHandle * db, const char * name, _SQLiteCreateCollationCallback callback) {
104-
if (callback) {
105-
return sqlite3_create_collation_v2((sqlite3 *)db, name, SQLITE_UTF8, (__bridge void *)callback, &__SQLiteCreateCollation, 0);
106-
} else {
107-
return sqlite3_create_collation_v2((sqlite3 *)db, name, 0, 0, 0, 0);
108-
}
109-
}
110-
11133
#pragma mark - FTS
11234

11335
typedef struct __SQLiteTokenizer {

0 commit comments

Comments
 (0)