Other than the quadratic matching, is there any other reason why ranks are used at all?
While the provided example was somewhat silly, there is a legitimate use case for this as a Sqlite wrapper:
/* All data types supported by sqlite (Int32, Int64, Double, String, UnsafeRawBufferPointer) as
well as their optionals implement this protocol in order to allow border crossing. */
public protocol SqliteRepresentable {
@inlinable func bind(to: Sqlite.Statement, at: Int32) throws
}
/* Wraps a prepared statement and offers means to run it with optional parameters, iterate
the returned results or query the number of affected rows. */
public struct Statement {
@usableFromInline let statement: OpaquePointer
@inline(__always) fileprivate init(_ stmt: OpaquePointer) { statement = stmt }
@usableFromInline func run<T: Sequence<SqliteRepresentable>, R>(_ args: T, do cb: (inout Int32) throws -> R) throws -> R {
var i = Int32(1); for arg in args {
try arg.bind(to: self, at: i)
i += 1
}
defer { sqlite3_reset(statement) }
var code = sqlite3_step(statement)
let res = try cb(&code)
guard code == SQLITE_DONE else { throw Error(rawValue: code) }
return res
}
@inlinable public subscript(_ col: Int32) -> Bytes! {
guard let ptr = sqlite3_column_blob(statement, col) else { return nil }
return Bytes(start: ptr, count: Int(sqlite3_column_bytes(statement, col)))
}
@inlinable public subscript(_ col: Int32) -> Int32! {
SQLITE_NULL == sqlite3_column_type(statement, col) ? nil : sqlite3_column_int(statement, col)
}
@inlinable public subscript(_ col: Int32) -> Int64! {
SQLITE_NULL == sqlite3_column_type(statement, col) ? nil : sqlite3_column_int64(statement, col)
}
@inlinable public subscript(_ col: Int32) -> Double! {
SQLITE_NULL == sqlite3_column_type(statement, col) ? nil : sqlite3_column_double(statement, col)
}
@inlinable public subscript(_ col: Int32) -> String! {
guard let ptr = sqlite3_column_text(statement, col) else { return nil }
return String(cString: ptr)
}
/* Binds the first numbered `args` of the query to the provided values, runs the
statement and returns the number of affected rows. */
@inlinable @discardableResult public func callAsFunction(_ args: SqliteRepresentable...) throws -> Int32 {
try run(args) { code in sqlite3_changes(sqlite3_db_handle(statement)) }
}
/* Binds the first numbered `args` of the query to the provided values, runs the
statement and invokes `do` for each row. */
@inlinable public func callAsFunction(_ args: SqliteRepresentable..., do cb: () throws -> ()) throws {
try run(args) { code in
while code == SQLITE_ROW {
do { try cb() }
catch Error.DONE { return }
code = sqlite3_step(statement)
}
}
}
}
Usage:
let query = "select id, name from users where email = ?"
query("bob@example.com") {
print(query[0] as Int64, query[1] as String)
}
It might not be the sanest interface out there, but I figure that there's usually enough context to make this type safe. At one point I was casting a column to UInt32 without an as Int64
qualifier and was expecting a compiler error which I never got.
At the time I only considered that I wanted to use the higher bit of Int32 as unsigned, but then I went through:
- this might be safe overall, but will generate an unnecessary itoa & atoi pair into
- this converts to a double, then back to an int which is fine in the
UInt32
case but then:
func test() -> Int64 { Int64.max }
func test() -> Float64 { Float64(Int64.max) }
Int64(test() as Int64) // okay
Int64(test()) // crash due to rounding error, needs `.nextDown`