Files

197 lines
5.3 KiB
Swift

import Foundation
// MARK: - Public
extension String {
/// Returns the receiver, quoted for safe insertion as an identifier in an
/// SQL query.
///
/// db.execute(sql: "SELECT * FROM \(tableName.quotedDatabaseIdentifier)")
public var quotedDatabaseIdentifier: String {
// See <https://www.sqlite.org/lang_keywords.html>
return "\"\(self)\""
}
}
/// Return as many question marks separated with commas as the *count* argument.
///
/// databaseQuestionMarks(count: 3) // "?,?,?"
public func databaseQuestionMarks(count: Int) -> String {
repeatElement("?", count: count).joined(separator: ",")
}
// MARK: - Internal
/// Reserved for GRDB: do not use.
@inline(__always)
@inlinable
func GRDBPrecondition(
_ condition: @autoclosure() -> Bool,
_ message: @autoclosure() -> String = "",
file: StaticString = #file,
line: UInt = #line)
{
// Custom precondition function which aims at solving
// <https://bugs.swift.org/browse/SR-905> and
// <https://github.com/groue/GRDB.swift/issues/37>
if !condition() {
fatalError(message(), file: file, line: line)
}
}
func fatalError<E: Error>(_ error: E) -> Never {
try! { throw error }()
}
// Workaround Swift inconvenience around factory methods of non-final classes
func cast<T, U>(_ value: T) -> U? {
value as? U
}
extension RangeReplaceableCollection {
/// Removes the first object that matches *predicate*.
mutating func removeFirst(where predicate: (Element) throws -> Bool) rethrows {
if let index = try firstIndex(where: predicate) {
remove(at: index)
}
}
}
extension Dictionary {
/// Removes the first object that matches *predicate*.
mutating func removeFirst(where predicate: (Element) throws -> Bool) rethrows {
if let index = try firstIndex(where: predicate) {
remove(at: index)
}
}
}
extension DispatchQueue {
private static var mainKey: DispatchSpecificKey<()> = {
let key = DispatchSpecificKey<()>()
DispatchQueue.main.setSpecific(key: key, value: ())
return key
}()
static var isMain: Bool {
DispatchQueue.getSpecific(key: mainKey) != nil
}
}
extension Sequence {
func countElements(where predicate: (Element) throws -> Bool) rethrows -> Int {
var count = 0
for e in self where try predicate(e) {
count += 1
}
return count
}
}
/// Makes sure the `finally` function is executed even if `execute` throws, and
/// rethrows the eventual first thrown error.
///
/// Usage:
///
/// try setup()
/// try throwingFirstError(
/// execute: work,
/// finally: cleanup)
func throwingFirstError<T>(execute: () throws -> T, finally: () throws -> Void) throws -> T {
var result: T?
var firstError: Error?
do {
result = try execute()
} catch {
firstError = error
}
do {
try finally()
} catch {
if firstError == nil {
firstError = error
}
}
if let firstError {
throw firstError
}
return result!
}
struct PrintOutputStream: TextOutputStream {
func write(_ string: String) {
Swift.print(string)
}
}
/// Concatenates two functions
func concat(_ rhs: (() -> Void)?, _ lhs: (() -> Void)?) -> (() -> Void)? {
switch (rhs, lhs) {
case let (rhs, nil):
return rhs
case let (nil, lhs):
return lhs
case let (rhs?, lhs?):
return {
rhs()
lhs()
}
}
}
/// Concatenates two functions
func concat<T>(_ rhs: ((T) -> Void)?, _ lhs: ((T) -> Void)?) -> ((T) -> Void)? {
switch (rhs, lhs) {
case let (rhs, nil):
return rhs
case let (nil, lhs):
return lhs
case let (rhs?, lhs?):
return {
rhs($0)
lhs($0)
}
}
}
extension NSLocking {
func synchronized<T>(
_ message: @autoclosure () -> String = #function,
_ block: () throws -> T)
rethrows -> T
{
lock()
defer { unlock() }
return try block()
}
// // Verbose version which helps understanding locking bugs
// func synchronized<T>(_ message: @autoclosure () -> String = "", _ block: () throws -> T) rethrows -> T {
// let queueName = String(validatingUTF8: __dispatch_queue_get_label(nil))
// print("\(queueName ?? "n/d"): \(message()) acquiring \(self)")
// lock()
// print("\(queueName ?? "n/d"): \(message()) acquired \(self)")
// defer {
// print("\(queueName ?? "n/d"): \(message()) releasing \(self)")
// unlock()
// print("\(queueName ?? "n/d"): \(message()) released \(self)")
// }
// return try block()
// }
/// Performs the side effect outside of the synchronized block. This allows
/// avoiding deadlocks, when the side effect feedbacks.
func synchronized(
_ message: @autoclosure () -> String = #function,
_ block: (inout (() -> Void)?) -> Void)
{
var sideEffect: (() -> Void)?
synchronized(message()) { block(&sideEffect) }
sideEffect?()
}
}
#if !canImport(ObjectiveC)
@inlinable func autoreleasepool<Result>(invoking body: () throws -> Result) rethrows -> Result { try body() }
#endif