From 43ced9b2f0730ed84e813c8067f3e2bee0b2cad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwendal=20Roue=CC=81?= Date: Sun, 17 Mar 2024 16:50:05 +0100 Subject: [PATCH] Trivial Sendable conformances Either added, either made explicitly unavailable. --- GRDB/Core/Configuration.swift | 2 +- GRDB/Core/Cursor.swift | 40 +++++++++++++++++++ GRDB/Core/Database+Schema.swift | 12 +++--- GRDB/Core/Database+Statements.swift | 5 +++ GRDB/Core/Database.swift | 29 ++++++++++---- GRDB/Core/DatabaseBackupProgress.swift | 2 +- GRDB/Core/DatabaseRegion.swift | 2 +- GRDB/Core/DatabaseValueConvertible.swift | 5 +++ GRDB/Core/FetchRequest.swift | 5 +++ GRDB/Core/Row.swift | 13 +++++- GRDB/Core/RowAdapter.swift | 8 ++-- GRDB/Core/Statement.swift | 5 +++ GRDB/Core/StatementColumnConvertible.swift | 5 +++ .../Foundation/DatabaseDateComponents.swift | 4 +- GRDB/Core/TransactionObserver.swift | 11 +++-- GRDB/Dump/Database+Dump.swift | 2 +- GRDB/Dump/DumpFormats/DebugDumpFormat.swift | 2 +- GRDB/Dump/DumpFormats/JSONDumpFormat.swift | 2 +- GRDB/Dump/DumpFormats/LineDumpFormat.swift | 2 +- GRDB/Dump/DumpFormats/ListDumpFormat.swift | 2 +- GRDB/Dump/DumpFormats/QuoteDumpFormat.swift | 2 +- GRDB/FTS/FTS3.swift | 7 +++- GRDB/FTS/FTS3Pattern.swift | 2 +- GRDB/FTS/FTS3TokenizerDescriptor.swift | 2 +- GRDB/FTS/FTS4.swift | 10 +++++ GRDB/FTS/FTS5.swift | 12 +++++- GRDB/FTS/FTS5Pattern.swift | 2 +- GRDB/FTS/FTS5Tokenizer.swift | 2 +- GRDB/FTS/FTS5TokenizerDescriptor.swift | 2 +- GRDB/FTS/FTS5WrapperTokenizer.swift | 2 +- GRDB/JSON/JSONColumn.swift | 2 +- GRDB/Migration/DatabaseMigrator.swift | 2 +- GRDB/QueryInterface/ForeignKey.swift | 2 +- GRDB/QueryInterface/SQL/Column.swift | 2 +- GRDB/QueryInterface/SQL/SQLExpression.swift | 2 +- GRDB/QueryInterface/SQL/SQLFunctions.swift | 2 +- GRDB/QueryInterface/SQL/SQLSelection.swift | 2 +- GRDB/QueryInterface/SQL/Table.swift | 2 +- .../Schema/ColumnDefinition.swift | 7 +++- .../Schema/Database+SchemaDefinition.swift | 2 +- .../Schema/ForeignKeyDefinition.swift | 5 +++ .../Schema/IndexDefinition.swift | 2 +- .../Schema/TableAlteration.swift | 5 +++ .../Schema/TableDefinition.swift | 7 +++- GRDB/Record/FetchableRecord+Decodable.swift | 1 + GRDB/Record/FetchableRecord.swift | 5 +++ GRDB/Record/MutablePersistableRecord.swift | 2 +- GRDB/Utils/Inflections.swift | 2 +- .../SharedValueObservation.swift | 2 +- .../ValueObservationScheduler.swift | 2 +- 50 files changed, 203 insertions(+), 56 deletions(-) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index 780ce452a4..6b261902b6 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -294,7 +294,7 @@ public struct Configuration { /// connection is opened. /// /// Related SQLite documentation: - public enum JournalModeConfiguration { + public enum JournalModeConfiguration: Sendable { /// The default setup has ``DatabaseQueue`` perform no specific /// configuration of the journal mode, and ``DatabasePool`` /// configure the database for the WAL mode (just like the diff --git a/GRDB/Core/Cursor.swift b/GRDB/Core/Cursor.swift index 58834bb859..b8ee021552 100644 --- a/GRDB/Core/Cursor.swift +++ b/GRDB/Core/Cursor.swift @@ -733,6 +733,11 @@ public final class AnyCursor: Cursor { } } +// Explicit non-conformance to Sendable: a type-erased cursor can't be more +// sendable than non-sendable cursors (such as `DatabaseCursor`). +@available(*, unavailable) +extension AnyCursor: Sendable { } + /// A `Cursor` that consumes and drops n elements from an underlying `Base` /// cursor before possibly returning the first available element. public final class DropFirstCursor { @@ -747,6 +752,11 @@ public final class DropFirstCursor { } } +// Explicit non-conformance to Sendable: `DropFirstCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension DropFirstCursor: Sendable { } + extension DropFirstCursor: Cursor { public func next() throws -> Base.Element? { while dropped < limit { @@ -773,6 +783,11 @@ public final class DropWhileCursor { } } +// Explicit non-conformance to Sendable: `DropWhileCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension DropWhileCursor: Sendable { } + extension DropWhileCursor: Cursor { public func next() throws -> Base.Element? { if predicateHasFailed { @@ -818,6 +833,11 @@ public final class EnumeratedCursor { } } +// Explicit non-conformance to Sendable: `EnumeratedCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension EnumeratedCursor: Sendable { } + extension EnumeratedCursor: Cursor { public func next() throws -> (Int, Base.Element)? { guard let element = try base.next() else { return nil } @@ -875,6 +895,11 @@ public final class FlattenCursor where Base.Element: Cursor { } } +// Explicit non-conformance to Sendable: `EnumeratedCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FlattenCursor: Sendable { } + extension FlattenCursor: Cursor { public func next() throws -> Base.Element.Element? { while true { @@ -901,6 +926,11 @@ public final class MapCursor { } } +// Explicit non-conformance to Sendable: There is no known reason for making +// it thread-safe (`transform` a Sendable closure). +@available(*, unavailable) +extension MapCursor: Sendable { } + extension MapCursor: Cursor { public func next() throws -> Element? { guard let element = try base.next() else { return nil } @@ -927,6 +957,11 @@ public final class PrefixCursor { } } +// Explicit non-conformance to Sendable: `PrefixCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension PrefixCursor: Sendable { } + extension PrefixCursor: Cursor { public func next() throws -> Base.Element? { if taken >= maxLength { return nil } @@ -954,6 +989,11 @@ public final class PrefixWhileCursor { } } +// Explicit non-conformance to Sendable: `PrefixCursor` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension PrefixWhileCursor: Sendable { } + extension PrefixWhileCursor: Cursor { public func next() throws -> Base.Element? { if !predicateHasFailed, let nextElement = try base.next() { diff --git a/GRDB/Core/Database+Schema.swift b/GRDB/Core/Database+Schema.swift index f636f91698..878cbe72bf 100644 --- a/GRDB/Core/Database+Schema.swift +++ b/GRDB/Core/Database+Schema.swift @@ -997,7 +997,7 @@ extension Database { /// /// - [pragma `table_info`](https://www.sqlite.org/pragma.html#pragma_table_info) /// - [pragma `table_xinfo`](https://www.sqlite.org/pragma.html#pragma_table_xinfo) -public struct ColumnInfo: FetchableRecord { +public struct ColumnInfo: FetchableRecord, Sendable { let cid: Int let hidden: Int? @@ -1083,9 +1083,9 @@ public struct ColumnInfo: FetchableRecord { /// /// - [pragma `index_list`](https://www.sqlite.org/pragma.html#pragma_index_list) /// - [pragma `index_info`](https://www.sqlite.org/pragma.html#pragma_index_info) -public struct IndexInfo { +public struct IndexInfo: Sendable{ /// The origin of an index. - public struct Origin: RawRepresentable, Equatable, DatabaseValueConvertible { + public struct Origin: RawRepresentable, Equatable, DatabaseValueConvertible, Sendable { public var rawValue: String public init(rawValue: String) { @@ -1158,7 +1158,7 @@ public struct IndexInfo { /// ``` /// /// Related SQLite documentation: -public struct ForeignKeyViolation { +public struct ForeignKeyViolation: Sendable { /// The name of the table that contains the foreign key. public var originTable: String @@ -1307,7 +1307,7 @@ extension ForeignKeyViolation: CustomStringConvertible { /// pk.rowIDColumn // nil /// pk.isRowID // false /// ``` -public struct PrimaryKeyInfo { +public struct PrimaryKeyInfo: Sendable { private enum Impl { /// The hidden rowID. case hiddenRowID @@ -1433,7 +1433,7 @@ public struct PrimaryKeyInfo { /// `Database` method. /// /// Related SQLite documentation: [pragma `foreign_key_list`](https://www.sqlite.org/pragma.html#pragma_foreign_key_list). -public struct ForeignKeyInfo { +public struct ForeignKeyInfo: Sendable { /// The first column in the output of the `foreign_key_list` pragma. public var id: Int diff --git a/GRDB/Core/Database+Statements.swift b/GRDB/Core/Database+Statements.swift index 48d4ad74e0..061c5b3646 100644 --- a/GRDB/Core/Database+Statements.swift +++ b/GRDB/Core/Database+Statements.swift @@ -361,6 +361,11 @@ public class SQLStatementCursor { } } +// Explicit non-conformance to Sendable: database cursors must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension SQLStatementCursor: Sendable { } + extension SQLStatementCursor: Cursor { public func next() throws -> Statement? { guard offset < cString.count - 1 /* trailing \0 */ else { diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index d09c529403..ae705dbe1c 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -1729,6 +1729,11 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib } } +// Explicit non-conformance to Sendable: `Database` must be used from a +// serialized database access dispatch queue (see `SerializedDatabase`). +@available(*, unavailable) +extension Database: Sendable { } + #if SQLITE_HAS_CODEC extension Database { @@ -1854,7 +1859,7 @@ extension Database { /// The available checkpoint modes. /// /// Related SQLite documentation: - public enum CheckpointMode: CInt { + public enum CheckpointMode: CInt, Sendable { /// The `SQLITE_CHECKPOINT_PASSIVE` mode. case passive = 0 @@ -1873,7 +1878,7 @@ extension Database { /// Related SQLite documentation: /// - /// - - public struct CollationName: RawRepresentable, Hashable { + public struct CollationName: RawRepresentable, Hashable, Sendable { public let rawValue: String /// Creates a collation name. @@ -1962,7 +1967,7 @@ extension Database { /// An SQLite conflict resolution. /// /// Related SQLite documentation: - public enum ConflictResolution: String { + public enum ConflictResolution: String, Sendable { /// The `ROLLBACK` conflict resolution. case rollback = "ROLLBACK" @@ -1982,7 +1987,7 @@ extension Database { /// A foreign key action. /// /// Related SQLite documentation: - public enum ForeignKeyAction: String { + public enum ForeignKeyAction: String, Sendable { /// The `CASCADE` foreign key action. case cascade = "CASCADE" @@ -2005,7 +2010,7 @@ extension Database { /// ``Database/trace(options:_:)`` method. /// /// Related SQLite documentation: - public struct TracingOptions: OptionSet { + public struct TracingOptions: OptionSet, Sendable { /// The raw trace event code. public let rawValue: CInt @@ -2138,7 +2143,7 @@ extension Database { /// /// Related SQLite documentation: . @frozen - public enum TransactionCompletion { + public enum TransactionCompletion: Sendable { case commit case rollback } @@ -2146,7 +2151,7 @@ extension Database { /// A transaction kind. /// /// Related SQLite documentation: . - public enum TransactionKind: String { + public enum TransactionKind: String, Sendable { /// The `DEFERRED` transaction kind. case deferred = "DEFERRED" @@ -2179,3 +2184,13 @@ extension Database { } } } + +// Explicit non-conformance to Sendable: a trace event contains transient +// information. +@available(*, unavailable) +extension Database.TraceEvent: Sendable { } + +// Explicit non-conformance to Sendable: a trace event contains transient +// information. +@available(*, unavailable) +extension Database.TraceEvent.Statement: Sendable { } diff --git a/GRDB/Core/DatabaseBackupProgress.swift b/GRDB/Core/DatabaseBackupProgress.swift index 3119dfa5b6..52a4a56d5e 100644 --- a/GRDB/Core/DatabaseBackupProgress.swift +++ b/GRDB/Core/DatabaseBackupProgress.swift @@ -1,7 +1,7 @@ /// Describe the progress of a database backup. /// /// Related SQLite documentation: -public struct DatabaseBackupProgress { +public struct DatabaseBackupProgress: Sendable { /// The number of pages still to be backed up. /// /// It is the result of the `sqlite3_backup_remaining` function. diff --git a/GRDB/Core/DatabaseRegion.swift b/GRDB/Core/DatabaseRegion.swift index 0099ddb028..fddeb77d37 100644 --- a/GRDB/Core/DatabaseRegion.swift +++ b/GRDB/Core/DatabaseRegion.swift @@ -40,7 +40,7 @@ /// /// - ``isModified(byEventsOfKind:)`` /// - ``isModified(by:)`` -public struct DatabaseRegion { +public struct DatabaseRegion: Sendable { private let tableRegions: [CaseInsensitiveIdentifier: TableRegion]? private init(tableRegions: [CaseInsensitiveIdentifier: TableRegion]?) { diff --git a/GRDB/Core/DatabaseValueConvertible.swift b/GRDB/Core/DatabaseValueConvertible.swift index 47f54c5af2..df9b1b6939 100644 --- a/GRDB/Core/DatabaseValueConvertible.swift +++ b/GRDB/Core/DatabaseValueConvertible.swift @@ -222,6 +222,11 @@ public final class DatabaseValueCursor: Databas } } +// Explicit non-conformance to Sendable: database cursors must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension DatabaseValueCursor: Sendable { } + /// DatabaseValueConvertible comes with built-in methods that allow to fetch /// cursors, arrays, or single values: /// diff --git a/GRDB/Core/FetchRequest.swift b/GRDB/Core/FetchRequest.swift index 87ff4b3404..43115cab70 100644 --- a/GRDB/Core/FetchRequest.swift +++ b/GRDB/Core/FetchRequest.swift @@ -152,6 +152,11 @@ public struct PreparedRequest { } } +// Explicit non-conformance to Sendable: `PreparedRequest` contains +// a statement. +@available(*, unavailable) +extension PreparedRequest: Sendable { } + extension PreparedRequest: Refinable { } // MARK: - AdaptedFetchRequest diff --git a/GRDB/Core/Row.swift b/GRDB/Core/Row.swift index 4c3698f7ef..e11f35d1ff 100644 --- a/GRDB/Core/Row.swift +++ b/GRDB/Core/Row.swift @@ -245,6 +245,12 @@ public final class Row { } } +// Explicit non-conformance to Sendable: a row contains transient +// information. TODO GRDB7: split non sendable statement rows from sendable +// copied rows. +@available(*, unavailable) +extension Row: Sendable { } + extension Row { // MARK: - Columns @@ -1377,6 +1383,11 @@ public final class RowCursor: DatabaseCursor { public func _element(sqliteStatement: SQLiteStatement) -> Row { _row } } +// Explicit non-conformance to Sendable: database cursors must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension RowCursor: Sendable { } + extension Row { // MARK: - Fetching From Prepared Statement @@ -2059,7 +2070,7 @@ typealias RowIndex = Row.Index extension Row { /// An index to a (column, value) pair in a ``Row``. - public struct Index { + public struct Index: Sendable { let index: Int init(_ index: Int) { self.index = index } } diff --git a/GRDB/Core/RowAdapter.swift b/GRDB/Core/RowAdapter.swift index a17062460f..a077e58152 100644 --- a/GRDB/Core/RowAdapter.swift +++ b/GRDB/Core/RowAdapter.swift @@ -378,7 +378,7 @@ extension RowAdapter { /// /// This limit adapter may turn out useful in some narrow use cases. You'll /// be happy to find it when you need it. -public struct EmptyRowAdapter: RowAdapter { +public struct EmptyRowAdapter: RowAdapter, Sendable { /// Creates an `EmptyRowAdapter`. public init() { } @@ -403,7 +403,7 @@ public struct EmptyRowAdapter: RowAdapter { /// /// Note that columns that are not present in the dictionary are not present /// in the resulting adapted row. -public struct ColumnMapping: RowAdapter { +public struct ColumnMapping: RowAdapter, Sendable { /// A dictionary from mapped column names to column names in a base row. let mapping: [String: String] @@ -444,7 +444,7 @@ public struct ColumnMapping: RowAdapter { /// // [c:2, d: 3] /// try Row.fetchOne(db, sql: sql, adapter: adapter)! /// ``` -public struct SuffixRowAdapter: RowAdapter { +public struct SuffixRowAdapter: RowAdapter, Sendable { /// The suffix index let index: Int @@ -473,7 +473,7 @@ public struct SuffixRowAdapter: RowAdapter { /// // [b:1 c:2] /// try Row.fetchOne(db, sql: sql, adapter: adapter) /// ``` -public struct RangeRowAdapter: RowAdapter { +public struct RangeRowAdapter: RowAdapter, Sendable { /// The range let range: CountableRange diff --git a/GRDB/Core/Statement.swift b/GRDB/Core/Statement.swift index 5bec60a162..e1a90a1082 100644 --- a/GRDB/Core/Statement.swift +++ b/GRDB/Core/Statement.swift @@ -623,6 +623,11 @@ public final class Statement { } } +// Explicit non-conformance to Sendable: statements must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension Statement: Sendable { } + extension Statement: CustomStringConvertible { public var description: String { SchedulingWatchdog.allows(database) ? sql : "Statement" diff --git a/GRDB/Core/StatementColumnConvertible.swift b/GRDB/Core/StatementColumnConvertible.swift index 3b18bcb9af..cb081ec63d 100644 --- a/GRDB/Core/StatementColumnConvertible.swift +++ b/GRDB/Core/StatementColumnConvertible.swift @@ -241,6 +241,11 @@ where Value: DatabaseValueConvertible & StatementColumnConvertible } } +// Explicit non-conformance to Sendable: database cursors must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension FastDatabaseValueCursor: Sendable { } + /// Types that adopt both DatabaseValueConvertible and /// StatementColumnConvertible can be efficiently initialized from /// database values. diff --git a/GRDB/Core/Support/Foundation/DatabaseDateComponents.swift b/GRDB/Core/Support/Foundation/DatabaseDateComponents.swift index 954edb350b..d4ebba478a 100644 --- a/GRDB/Core/Support/Foundation/DatabaseDateComponents.swift +++ b/GRDB/Core/Support/Foundation/DatabaseDateComponents.swift @@ -1,10 +1,10 @@ import Foundation /// A database value that holds date components. -public struct DatabaseDateComponents { +public struct DatabaseDateComponents: Sendable { /// The SQLite formats for date components. - public enum Format: String { + public enum Format: String, Sendable { /// The format "yyyy-MM-dd". case YMD = "yyyy-MM-dd" diff --git a/GRDB/Core/TransactionObserver.swift b/GRDB/Core/TransactionObserver.swift index 4ce21468b1..d45b3b1206 100644 --- a/GRDB/Core/TransactionObserver.swift +++ b/GRDB/Core/TransactionObserver.swift @@ -135,7 +135,7 @@ extension Database { } /// The extent of the observation performed by a ``TransactionObserver``. - public enum TransactionObservationExtent { + public enum TransactionObservationExtent: Sendable { /// Observation lasts until observer is deallocated. case observerLifetime /// Observation lasts until the next transaction. @@ -1056,7 +1056,7 @@ struct StatementObservation { /// See the ``TransactionObserver/observes(eventsOfKind:)`` method in the /// ``TransactionObserver`` protocol for more information. @frozen -public enum DatabaseEventKind { +public enum DatabaseEventKind: Sendable { /// The insertion of a row in a database table. case insert(tableName: String) @@ -1109,7 +1109,7 @@ protocol DatabaseEventProtocol { /// ``TransactionObserver`` protocol for more information. public struct DatabaseEvent { /// An event kind. - public enum Kind: CInt { + public enum Kind: CInt, Sendable { /// An insertion event case insert = 18 // SQLITE_INSERT @@ -1173,6 +1173,11 @@ public struct DatabaseEvent { } } +// Explicit non-conformance to Sendable: this type can't be made Sendable +// until GRDB7 where we can distinguish between a transient event and its copy. +@available(*, unavailable) +extension DatabaseEvent: Sendable { } + extension DatabaseEvent: DatabaseEventProtocol { func send(to observer: TransactionObservation) { observer.databaseDidChange(with: self) diff --git a/GRDB/Dump/Database+Dump.swift b/GRDB/Dump/Database+Dump.swift index e98716edc3..33edfda640 100644 --- a/GRDB/Dump/Database+Dump.swift +++ b/GRDB/Dump/Database+Dump.swift @@ -308,7 +308,7 @@ extension Database { } /// Options for printing table names. -public enum DumpTableHeaderOptions { +public enum DumpTableHeaderOptions: Sendable { /// Table names are only printed when several tables are printed. case automatic diff --git a/GRDB/Dump/DumpFormats/DebugDumpFormat.swift b/GRDB/Dump/DumpFormats/DebugDumpFormat.swift index 58b8f97482..02f2f11304 100644 --- a/GRDB/Dump/DumpFormats/DebugDumpFormat.swift +++ b/GRDB/Dump/DumpFormats/DebugDumpFormat.swift @@ -17,7 +17,7 @@ import Foundation /// // Craig|200 /// try db.dumpRequest(Player.all(), format: .debug()) /// ``` -public struct DebugDumpFormat { +public struct DebugDumpFormat: Sendable { /// A boolean value indicating if column labels are printed as the first /// line of output. public var header: Bool diff --git a/GRDB/Dump/DumpFormats/JSONDumpFormat.swift b/GRDB/Dump/DumpFormats/JSONDumpFormat.swift index 0e039863bf..7e3bc61d5b 100644 --- a/GRDB/Dump/DumpFormats/JSONDumpFormat.swift +++ b/GRDB/Dump/DumpFormats/JSONDumpFormat.swift @@ -27,7 +27,7 @@ import Foundation /// encoder.outputFormatting = .prettyPrinted /// try db.dumpRequest(Player.all(), format: .json(encoder)) /// ``` -public struct JSONDumpFormat { +public struct JSONDumpFormat: Sendable { /// The default `JSONEncoder` for database values. /// /// It is configured so that blob values (`Data`) are encoded in the diff --git a/GRDB/Dump/DumpFormats/LineDumpFormat.swift b/GRDB/Dump/DumpFormats/LineDumpFormat.swift index debc28956c..a0c9f9a1fd 100644 --- a/GRDB/Dump/DumpFormats/LineDumpFormat.swift +++ b/GRDB/Dump/DumpFormats/LineDumpFormat.swift @@ -13,7 +13,7 @@ import Foundation /// // score = 1000 /// try db.dumpRequest(Player.all(), format: .line()) /// ``` -public struct LineDumpFormat { +public struct LineDumpFormat: Sendable { /// The string to print for NULL values. public var nullValue: String diff --git a/GRDB/Dump/DumpFormats/ListDumpFormat.swift b/GRDB/Dump/DumpFormats/ListDumpFormat.swift index 4062095415..c256af4c82 100644 --- a/GRDB/Dump/DumpFormats/ListDumpFormat.swift +++ b/GRDB/Dump/DumpFormats/ListDumpFormat.swift @@ -14,7 +14,7 @@ import Foundation /// // Craig|200 /// try db.dumpRequest(Player.all(), format: .list()) /// ``` -public struct ListDumpFormat { +public struct ListDumpFormat: Sendable { /// A boolean value indicating if column labels are printed as the first /// line of output. public var header: Bool diff --git a/GRDB/Dump/DumpFormats/QuoteDumpFormat.swift b/GRDB/Dump/DumpFormats/QuoteDumpFormat.swift index 2fd8587a99..3c6ae5c17a 100644 --- a/GRDB/Dump/DumpFormats/QuoteDumpFormat.swift +++ b/GRDB/Dump/DumpFormats/QuoteDumpFormat.swift @@ -9,7 +9,7 @@ /// // 'Craig',200 /// try db.dumpRequest(Player.all(), format: .quote()) /// ``` -public struct QuoteDumpFormat { +public struct QuoteDumpFormat: Sendable { /// A boolean value indicating if column labels are printed as the first /// line of output. public var header: Bool diff --git a/GRDB/FTS/FTS3.swift b/GRDB/FTS/FTS3.swift index cb308cd069..80e677ae18 100644 --- a/GRDB/FTS/FTS3.swift +++ b/GRDB/FTS/FTS3.swift @@ -29,7 +29,7 @@ /// - ``tokenize(_:withTokenizer:)`` public struct FTS3 { /// Options for Latin script characters. - public enum Diacritics { + public enum Diacritics: Sendable { /// Do not remove diacritics from Latin script characters. This option /// matches the `remove_diacritics=0` tokenizer argument. /// @@ -183,3 +183,8 @@ public final class FTS3TableDefinition { columns.append(name) } } + +// Explicit non-conformance to Sendable: `FTS3TableDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FTS3TableDefinition: Sendable { } diff --git a/GRDB/FTS/FTS3Pattern.swift b/GRDB/FTS/FTS3Pattern.swift index 9862566f2e..af6e82170d 100644 --- a/GRDB/FTS/FTS3Pattern.swift +++ b/GRDB/FTS/FTS3Pattern.swift @@ -16,7 +16,7 @@ /// - ``init(matchingAllTokensIn:)`` /// - ``init(matchingAnyTokenIn:)`` /// - ``init(matchingPhrase:)`` -public struct FTS3Pattern { +public struct FTS3Pattern: Sendable { /// The raw pattern string. /// /// It is guaranteed to be a valid FTS3/4 pattern. diff --git a/GRDB/FTS/FTS3TokenizerDescriptor.swift b/GRDB/FTS/FTS3TokenizerDescriptor.swift index 378af557c1..14b2a3e81e 100644 --- a/GRDB/FTS/FTS3TokenizerDescriptor.swift +++ b/GRDB/FTS/FTS3TokenizerDescriptor.swift @@ -20,7 +20,7 @@ /// - ``simple`` /// - ``unicode61(diacritics:separators:tokenCharacters:)`` /// - ``FTS3/Diacritics`` -public struct FTS3TokenizerDescriptor { +public struct FTS3TokenizerDescriptor: Sendable { let name: String let arguments: [String] diff --git a/GRDB/FTS/FTS4.swift b/GRDB/FTS/FTS4.swift index 36e5e7c748..ef9a54f5e3 100644 --- a/GRDB/FTS/FTS4.swift +++ b/GRDB/FTS/FTS4.swift @@ -313,6 +313,11 @@ public final class FTS4TableDefinition { } } +// Explicit non-conformance to Sendable: `FTS4TableDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FTS4TableDefinition: Sendable { } + /// Describes a column in an ``FTS4`` virtual table. /// /// You get instances of `FTS4ColumnDefinition` when you create an ``FTS4`` @@ -377,6 +382,11 @@ public final class FTS4ColumnDefinition { } } +// Explicit non-conformance to Sendable: `FTS4ColumnDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FTS4ColumnDefinition: Sendable { } + extension Database { /// Deletes the synchronization triggers for a synchronized FTS4 table. /// diff --git a/GRDB/FTS/FTS5.swift b/GRDB/FTS/FTS5.swift index 43daaf5dda..a18da5a3f0 100644 --- a/GRDB/FTS/FTS5.swift +++ b/GRDB/FTS/FTS5.swift @@ -44,7 +44,7 @@ public struct FTS5 { /// tokenizer argument. /// /// Related SQLite documentation: - public enum Diacritics { + public enum Diacritics: Sendable { /// Do not remove diacritics from Latin script characters. This /// option matches the raw "remove_diacritics=0" tokenizer argument. case keep @@ -492,6 +492,11 @@ public final class FTS5TableDefinition { } } +// Explicit non-conformance to Sendable: `FTS5TableDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FTS5TableDefinition: Sendable { } + /// Describes a column in an ``FTS5`` virtual table. /// /// You get instances of `FTS5ColumnDefinition` when you create an ``FTS5`` @@ -534,6 +539,11 @@ public final class FTS5ColumnDefinition { } } +// Explicit non-conformance to Sendable: `FTS5ColumnDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension FTS5ColumnDefinition: Sendable { } + extension Column { /// The ``FTS5`` rank column. public static let rank = Column("rank") diff --git a/GRDB/FTS/FTS5Pattern.swift b/GRDB/FTS/FTS5Pattern.swift index c5e62a10eb..045a409a1b 100644 --- a/GRDB/FTS/FTS5Pattern.swift +++ b/GRDB/FTS/FTS5Pattern.swift @@ -16,7 +16,7 @@ /// - ``init(matchingAnyTokenIn:)`` /// - ``init(matchingPhrase:)`` /// - ``init(matchingPrefixPhrase:)`` -public struct FTS5Pattern { +public struct FTS5Pattern: Sendable { /// The raw pattern string. /// diff --git a/GRDB/FTS/FTS5Tokenizer.swift b/GRDB/FTS/FTS5Tokenizer.swift index 02db061538..8609a5ad72 100644 --- a/GRDB/FTS/FTS5Tokenizer.swift +++ b/GRDB/FTS/FTS5Tokenizer.swift @@ -16,7 +16,7 @@ public typealias FTS5TokenCallback = @convention(c) ( /// The reason why FTS5 is requesting tokenization. /// /// See the `FTS5_TOKENIZE_*` constants in . -public struct FTS5Tokenization: OptionSet { +public struct FTS5Tokenization: OptionSet, Sendable { public let rawValue: CInt public init(rawValue: CInt) { diff --git a/GRDB/FTS/FTS5TokenizerDescriptor.swift b/GRDB/FTS/FTS5TokenizerDescriptor.swift index b12a8acaaf..9750aa76fb 100644 --- a/GRDB/FTS/FTS5TokenizerDescriptor.swift +++ b/GRDB/FTS/FTS5TokenizerDescriptor.swift @@ -24,7 +24,7 @@ /// ### Instantiating Tokenizers /// /// - ``Database/makeTokenizer(_:)`` -public struct FTS5TokenizerDescriptor { +public struct FTS5TokenizerDescriptor: Sendable { /// The tokenizer components. /// /// For example: diff --git a/GRDB/FTS/FTS5WrapperTokenizer.swift b/GRDB/FTS/FTS5WrapperTokenizer.swift index 8b9de904aa..16ac1e1f96 100644 --- a/GRDB/FTS/FTS5WrapperTokenizer.swift +++ b/GRDB/FTS/FTS5WrapperTokenizer.swift @@ -4,7 +4,7 @@ import Foundation /// Flags that tell SQLite how to register a token. /// /// See the `FTS5_TOKEN_*` constants in . -public struct FTS5TokenFlags: OptionSet { +public struct FTS5TokenFlags: OptionSet, Sendable { public let rawValue: CInt public init(rawValue: CInt) { diff --git a/GRDB/JSON/JSONColumn.swift b/GRDB/JSON/JSONColumn.swift index 6ca345dd74..8f778d2b51 100644 --- a/GRDB/JSON/JSONColumn.swift +++ b/GRDB/JSON/JSONColumn.swift @@ -73,7 +73,7 @@ /// > .fetchAll(db) /// > } /// > ``` -public struct JSONColumn: ColumnExpression, SQLJSONExpressible { +public struct JSONColumn: ColumnExpression, SQLJSONExpressible, Sendable { public var name: String /// Creates a `JSONColumn` given its name. diff --git a/GRDB/Migration/DatabaseMigrator.swift b/GRDB/Migration/DatabaseMigrator.swift index 88b178c7ce..f4de96c69e 100644 --- a/GRDB/Migration/DatabaseMigrator.swift +++ b/GRDB/Migration/DatabaseMigrator.swift @@ -42,7 +42,7 @@ import Foundation /// - ``hasCompletedMigrations(_:)`` public struct DatabaseMigrator { /// Controls how a migration handle foreign keys constraints. - public enum ForeignKeyChecks { + public enum ForeignKeyChecks: Sendable { /// The migration runs with disabled foreign keys. /// /// Foreign keys are checked right before changes are committed on disk, diff --git a/GRDB/QueryInterface/ForeignKey.swift b/GRDB/QueryInterface/ForeignKey.swift index f89ee964ce..fbe27461d6 100644 --- a/GRDB/QueryInterface/ForeignKey.swift +++ b/GRDB/QueryInterface/ForeignKey.swift @@ -80,7 +80,7 @@ /// using: Book.translatorForeignKey) /// } /// ``` -public struct ForeignKey: Equatable { +public struct ForeignKey: Equatable, Sendable { var originColumns: [String] var destinationColumns: [String]? diff --git a/GRDB/QueryInterface/SQL/Column.swift b/GRDB/QueryInterface/SQL/Column.swift index a81c07d0a1..535166789e 100644 --- a/GRDB/QueryInterface/SQL/Column.swift +++ b/GRDB/QueryInterface/SQL/Column.swift @@ -92,7 +92,7 @@ extension ColumnExpression where Self == Column { /// /// - ``init(_:)-5grmu`` /// - ``init(_:)-7xc4z`` -public struct Column { +public struct Column: Sendable { /// The hidden rowID column. public static let rowID = Column("rowid") diff --git a/GRDB/QueryInterface/SQL/SQLExpression.swift b/GRDB/QueryInterface/SQL/SQLExpression.swift index 3613bdb16c..c612827048 100644 --- a/GRDB/QueryInterface/SQL/SQLExpression.swift +++ b/GRDB/QueryInterface/SQL/SQLExpression.swift @@ -315,7 +315,7 @@ public struct SQLExpression { /// 1000.databaseValue] /// let request = Player.select(values.joined(operator: .add)) /// ``` - public struct AssociativeBinaryOperator: Hashable { + public struct AssociativeBinaryOperator: Hashable, Sendable { /// The SQL operator let sql: String diff --git a/GRDB/QueryInterface/SQL/SQLFunctions.swift b/GRDB/QueryInterface/SQL/SQLFunctions.swift index a6938dab5b..bb1253907b 100644 --- a/GRDB/QueryInterface/SQL/SQLFunctions.swift +++ b/GRDB/QueryInterface/SQL/SQLFunctions.swift @@ -408,7 +408,7 @@ extension SQLSpecificExpressible { /// A date modifier for SQLite date functions. /// /// Related SQLite documentation: -public enum SQLDateModifier: SQLSpecificExpressible { +public enum SQLDateModifier: SQLSpecificExpressible, Sendable { /// Adds the specified amount of seconds case second(Double) diff --git a/GRDB/QueryInterface/SQL/SQLSelection.swift b/GRDB/QueryInterface/SQL/SQLSelection.swift index 351b483775..c4ff88045b 100644 --- a/GRDB/QueryInterface/SQL/SQLSelection.swift +++ b/GRDB/QueryInterface/SQL/SQLSelection.swift @@ -324,7 +324,7 @@ extension SQLSelection: SQLSelectable { /// let players = try Player.select(AllColumns()).fetchAll(db) /// } /// ``` -public struct AllColumns { +public struct AllColumns: Sendable { /// The `*` selection. public init() { } } diff --git a/GRDB/QueryInterface/SQL/Table.swift b/GRDB/QueryInterface/SQL/Table.swift index 0bad29a8e4..c6de851c74 100644 --- a/GRDB/QueryInterface/SQL/Table.swift +++ b/GRDB/QueryInterface/SQL/Table.swift @@ -138,7 +138,7 @@ /// ### Database Observation Support /// /// - ``databaseRegion(_:)`` -public struct Table { +public struct Table: Sendable { /// The table name. public var tableName: String diff --git a/GRDB/QueryInterface/Schema/ColumnDefinition.swift b/GRDB/QueryInterface/Schema/ColumnDefinition.swift index 08b6119456..88cf0103a3 100644 --- a/GRDB/QueryInterface/Schema/ColumnDefinition.swift +++ b/GRDB/QueryInterface/Schema/ColumnDefinition.swift @@ -76,7 +76,7 @@ public final class ColumnDefinition { /// The kind of a generated column. /// /// Related SQLite documentation: - public enum GeneratedColumnQualification { + public enum GeneratedColumnQualification: Sendable { /// A `VIRTUAL` generated column. case virtual /// A `STORED` generated column. @@ -565,3 +565,8 @@ public final class ColumnDefinition { } } } + +// Explicit non-conformance to Sendable: `ColumnDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension ColumnDefinition: Sendable { } diff --git a/GRDB/QueryInterface/Schema/Database+SchemaDefinition.swift b/GRDB/QueryInterface/Schema/Database+SchemaDefinition.swift index eb62d7e888..10b95ebc3a 100644 --- a/GRDB/QueryInterface/Schema/Database+SchemaDefinition.swift +++ b/GRDB/QueryInterface/Schema/Database+SchemaDefinition.swift @@ -681,7 +681,7 @@ extension Database { } /// View creation options -public struct ViewOptions: OptionSet { +public struct ViewOptions: OptionSet, Sendable { public let rawValue: Int public init(rawValue: Int) { self.rawValue = rawValue } diff --git a/GRDB/QueryInterface/Schema/ForeignKeyDefinition.swift b/GRDB/QueryInterface/Schema/ForeignKeyDefinition.swift index 7da337ec6f..e7754a0527 100644 --- a/GRDB/QueryInterface/Schema/ForeignKeyDefinition.swift +++ b/GRDB/QueryInterface/Schema/ForeignKeyDefinition.swift @@ -104,3 +104,8 @@ public final class ForeignKeyDefinition { throw DatabaseError.noSuchTable(name) } } + +// Explicit non-conformance to Sendable: `ForeignKeyDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension ForeignKeyDefinition: Sendable { } diff --git a/GRDB/QueryInterface/Schema/IndexDefinition.swift b/GRDB/QueryInterface/Schema/IndexDefinition.swift index 616d8d8868..567c4beffd 100644 --- a/GRDB/QueryInterface/Schema/IndexDefinition.swift +++ b/GRDB/QueryInterface/Schema/IndexDefinition.swift @@ -7,7 +7,7 @@ struct IndexDefinition { } /// Index creation options -public struct IndexOptions: OptionSet { +public struct IndexOptions: OptionSet, Sendable { public let rawValue: Int public init(rawValue: Int) { self.rawValue = rawValue } diff --git a/GRDB/QueryInterface/Schema/TableAlteration.swift b/GRDB/QueryInterface/Schema/TableAlteration.swift index a22b41991c..c731e7ea54 100644 --- a/GRDB/QueryInterface/Schema/TableAlteration.swift +++ b/GRDB/QueryInterface/Schema/TableAlteration.swift @@ -161,3 +161,8 @@ public final class TableAlteration { alterations.append(.drop(name)) } } + +// Explicit non-conformance to Sendable: `TableAlteration` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension TableAlteration: Sendable { } diff --git a/GRDB/QueryInterface/Schema/TableDefinition.swift b/GRDB/QueryInterface/Schema/TableDefinition.swift index 40958d1c41..235c54bf88 100644 --- a/GRDB/QueryInterface/Schema/TableDefinition.swift +++ b/GRDB/QueryInterface/Schema/TableDefinition.swift @@ -1,5 +1,5 @@ /// Table creation options. -public struct TableOptions: OptionSet { +public struct TableOptions: OptionSet, Sendable { public let rawValue: Int public init(rawValue: Int) { self.rawValue = rawValue } @@ -753,3 +753,8 @@ public final class TableDefinition { literalConstraints.append(literal) } } + +// Explicit non-conformance to Sendable: `TableDefinition` is a mutable +// class and there is no known reason for making it thread-safe. +@available(*, unavailable) +extension TableDefinition: Sendable { } diff --git a/GRDB/Record/FetchableRecord+Decodable.swift b/GRDB/Record/FetchableRecord+Decodable.swift index e1d7db7156..563c0f877b 100644 --- a/GRDB/Record/FetchableRecord+Decodable.swift +++ b/GRDB/Record/FetchableRecord+Decodable.swift @@ -7,6 +7,7 @@ extension FetchableRecord where Self: Decodable { } } +// TODO GRDB7: make it a final class, and Sendable. /// An object that decodes fetchable records from database rows. /// /// The example below shows how to decode an instance of a simple `Player` diff --git a/GRDB/Record/FetchableRecord.swift b/GRDB/Record/FetchableRecord.swift index 9a5c5679b3..609279560f 100644 --- a/GRDB/Record/FetchableRecord.swift +++ b/GRDB/Record/FetchableRecord.swift @@ -854,6 +854,11 @@ public final class RecordCursor: DatabaseCursor { } } +// Explicit non-conformance to Sendable: database cursors must be used from +// a serialized database access dispatch queue. +@available(*, unavailable) +extension RecordCursor: Sendable { } + // MARK: - DatabaseDataDecodingStrategy /// `DatabaseDataDecodingStrategy` specifies how `FetchableRecord` types that diff --git a/GRDB/Record/MutablePersistableRecord.swift b/GRDB/Record/MutablePersistableRecord.swift index c9932e1c67..d26cb1cbcc 100644 --- a/GRDB/Record/MutablePersistableRecord.swift +++ b/GRDB/Record/MutablePersistableRecord.swift @@ -348,7 +348,7 @@ extension MutablePersistableRecord { /// See `MutablePersistableRecord.persistenceConflictPolicy`. /// /// See -public struct PersistenceConflictPolicy { +public struct PersistenceConflictPolicy: Sendable { /// The conflict resolution algorithm for insertions public let conflictResolutionForInsert: Database.ConflictResolution diff --git a/GRDB/Utils/Inflections.swift b/GRDB/Utils/Inflections.swift index 860b4d0ba8..9c845c2c6b 100644 --- a/GRDB/Utils/Inflections.swift +++ b/GRDB/Utils/Inflections.swift @@ -31,7 +31,7 @@ extension String { /// A type that controls GRDB string inflections. /// /// - note: [**🔥 EXPERIMENTAL**](https://github.com/groue/GRDB.swift/blob/master/README.md#what-are-experimental-features) -public struct Inflections { +public struct Inflections: Sendable { private var pluralizeRules: [(NSRegularExpression, String)] = [] private var singularizeRules: [(NSRegularExpression, String)] = [] private var uncountablesRegularExpressions: [String: NSRegularExpression] = [:] diff --git a/GRDB/ValueObservation/SharedValueObservation.swift b/GRDB/ValueObservation/SharedValueObservation.swift index 123c44c28c..0a0e742ae3 100644 --- a/GRDB/ValueObservation/SharedValueObservation.swift +++ b/GRDB/ValueObservation/SharedValueObservation.swift @@ -1,7 +1,7 @@ import Foundation /// The extent of the shared subscription to a ``SharedValueObservation``. -public enum SharedValueObservationExtent { +public enum SharedValueObservationExtent: Sendable { /// The ``SharedValueObservation`` starts a single database observation, /// which stops when the `SharedValueObservation` is deallocated and all /// subscriptions terminated. diff --git a/GRDB/ValueObservation/ValueObservationScheduler.swift b/GRDB/ValueObservation/ValueObservationScheduler.swift index 6ca3447cf9..ad3b5f246f 100644 --- a/GRDB/ValueObservation/ValueObservationScheduler.swift +++ b/GRDB/ValueObservation/ValueObservationScheduler.swift @@ -76,7 +76,7 @@ extension ValueObservationScheduler where Self == AsyncValueObservationScheduler /// A scheduler that notifies all values on the main `DispatchQueue`. The /// first value is immediately notified when the `ValueObservation` /// is started. -public struct ImmediateValueObservationScheduler: ValueObservationScheduler { +public struct ImmediateValueObservationScheduler: ValueObservationScheduler, Sendable { public init() { } public func immediateInitialValue() -> Bool {