Skip to content

Commit

Permalink
feat: Mark ParseObject and related types as Sendable (#174)
Browse files Browse the repository at this point in the history
* feat: Mark ParseObject and related types as Sendable

* more Sendable

* Update CHANGELOG.md

* More Sendable
  • Loading branch information
cbaker6 committed Jul 11, 2024
1 parent 55d9d22 commit 10ec67c
Show file tree
Hide file tree
Showing 22 changed files with 72 additions and 44 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.9.3...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.10.0...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
* _Contributing to this repo? Add info about your change here to be included in the next release_


### 5.10.0
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.9.3...5.10.0), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.10.0/documentation/parseswift)

__New features__
* Make many of the Parse protocols and types conform to Sendable ([#174](https://github.com/netreconlab/Parse-Swift/pull/174)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.9.3
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.9.2...5.9.3), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.9.3/documentation/parseswift)

Expand Down
6 changes: 6 additions & 0 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
707A3BF125B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };
707A3C1125B0A8E8000D215C /* ParseAnonymous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */; };
707A3C2025B14BD0000D215C /* ParseApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1F25B14BCF000D215C /* ParseApple.swift */; };
707DC1C02C3F5DE900FC1DFD /* InputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707DC1BF2C3F5DE900FC1DFD /* InputStream.swift */; };
7085DD9426CBF3A70033B977 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 7085DD9326CBF3A70033B977 /* Documentation.docc */; };
7085DDA326CC8A470033B977 /* ParseServer+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDA226CC8A470033B977 /* ParseServer+combine.swift */; };
7085DDB326D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
Expand Down Expand Up @@ -489,6 +490,7 @@
707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthentication.swift; sourceTree = "<group>"; };
707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymous.swift; sourceTree = "<group>"; };
707A3C1F25B14BCF000D215C /* ParseApple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseApple.swift; sourceTree = "<group>"; };
707DC1BF2C3F5DE900FC1DFD /* InputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputStream.swift; sourceTree = "<group>"; };
7085DD9326CBF3A70033B977 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = "<group>"; };
7085DDA226CC8A470033B977 /* ParseServer+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ParseServer+combine.swift"; sourceTree = "<group>"; };
7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationCombineTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1084,6 +1086,7 @@
706436A827341FD0007C6461 /* Date.swift */,
70C048C02880D7E500401689 /* Dictionary.swift */,
706436A327341F6E007C6461 /* Encodable.swift */,
707DC1BF2C3F5DE900FC1DFD /* InputStream.swift */,
9116F66E26A35D600082F6D6 /* URLCache.swift */,
F97B462C24D9C74400F4A88B /* URLSession.swift */,
);
Expand Down Expand Up @@ -1602,6 +1605,7 @@
916E207029D8C83100C21EC6 /* ParseRelationOperationable.swift in Sources */,
70B4E0BC2762F1D5004C9757 /* QueryConstraint.swift in Sources */,
70C167B427304F09009F4E30 /* Pointer+async.swift in Sources */,
707DC1C02C3F5DE900FC1DFD /* InputStream.swift in Sources */,
705025AE28456106008D6624 /* ParsePushStatusable.swift in Sources */,
F97B464A24D9C78B00F4A88B /* ParseOperationDelete.swift in Sources */,
705025CC284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */,
Expand Down Expand Up @@ -1918,6 +1922,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_VERSION = 5.0;
TVOS_DEPLOYMENT_TARGET = 13.0;
VERSIONING_SYSTEM = "apple-generic";
Expand Down Expand Up @@ -1982,6 +1987,7 @@
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_STRICT_CONCURRENCY = minimal;
SWIFT_VERSION = 5.0;
TVOS_DEPLOYMENT_TARGET = 13.0;
VALIDATE_PRODUCT = YES;
Expand Down
17 changes: 9 additions & 8 deletions Sources/ParseSwift/API/API+Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import FoundationNetworking
internal extension API {
// MARK: API.Command
// swiftlint:disable:next type_body_length
struct Command<T, U>: Encodable where T: ParseEncodable {
struct Command<T, U>: Encodable, Sendable where T: ParseEncodable, U: Sendable {
typealias ReturnType = U // swiftlint:disable:this nesting
let method: API.Method
let path: API.Endpoint
let body: T?
let mapper: ((Data) async throws -> U)
let mapper: (@Sendable (Data) async throws -> U)
let params: [String: String?]?
let uploadData: Data?
let uploadFile: URL?
Expand All @@ -36,7 +36,7 @@ internal extension API {
parseURL: URL? = nil,
otherURL: URL? = nil,
stream: InputStream? = nil,
mapper: @escaping ((Data) async throws -> U)) {
mapper: @escaping (@Sendable (Data) async throws -> U)) {
self.method = method
self.path = path
self.body = body
Expand Down Expand Up @@ -429,8 +429,9 @@ internal extension API.Command {
let acl = try? await ParseACL.defaultACL() {
object.ACL = acl
}
let mapper = { (data) -> V in
try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: object)
let updatedObject = object
let mapper = { @Sendable (data) -> V in
try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: updatedObject)
}
return API.Command<V, V>(method: .POST,
path: try await object.endpoint(.POST),
Expand All @@ -444,7 +445,7 @@ internal extension API.Command {
throw ParseError(code: .missingObjectId,
message: "objectId must not be nil")
}
let mapper = { (mapperData: Data) -> V in
let mapper = { @Sendable (mapperData: Data) -> V in
var updatedObject = object
updatedObject.originalData = nil
updatedObject = try ParseCoding
Expand All @@ -471,7 +472,7 @@ internal extension API.Command {
throw ParseError(code: .missingObjectId,
message: "objectId must not be nil")
}
let mapper = { (mapperData: Data) -> V in
let mapper = { @Sendable (mapperData: Data) -> V in
var updatedObject = object
updatedObject.originalData = nil
updatedObject = try ParseCoding
Expand Down Expand Up @@ -530,7 +531,7 @@ internal extension API.Command where T: ParseObject {
mapper: command.mapper)
}

let mapper = { (data: Data) -> [Result<T, ParseError>] in
let mapper = { @Sendable (data: Data) -> [Result<T, ParseError>] in

let decodingType = [BatchResponseItem<BatchResponse>].self
do {
Expand Down
8 changes: 4 additions & 4 deletions Sources/ParseSwift/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import FoundationNetworking
/// The REST API for communicating with a Parse Server.
public struct API {

public enum Method: String, Encodable {
public enum Method: String, Encodable, Sendable {
case GET, POST, PUT, PATCH, DELETE
}

public enum Endpoint: Encodable {
public enum Endpoint: Encodable, Sendable {
case batch
case objects(className: String)
case object(className: String, objectId: String)
Expand Down Expand Up @@ -139,7 +139,7 @@ public struct API {
public typealias Options = Set<API.Option>

/// Options available to send to Parse Server.
public enum Option: Hashable {
public enum Option: Hashable, Sendable {

/// Use the primaryKey/masterKey if it was provided during initial configuraration.
case usePrimaryKey
Expand All @@ -164,7 +164,7 @@ public struct API {
case tags([String: String])
/// Add context.
/// - warning: Requires Parse Server 5.0.0+.
case context(Encodable)
case context(Encodable & Sendable)
/// The caching policy to use for a specific http request. Determines when to
/// return a response from the cache. See Apple's
/// [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/API/BatchUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ typealias ParseObjectBatchResponseEncodablePointer<U> = [(Result<PointerType, Pa
typealias RESTBatchCommandTypeEncodablePointer<T> = API.NonParseBodyCommand<ParseObjectBatchCommandEncodablePointer<T>, ParseObjectBatchResponseEncodablePointer<Encodable>> where T: Encodable
// swiftlint:enable line_length

internal struct BatchCommand<T, U>: ParseEncodable where T: ParseEncodable {
internal struct BatchCommand<T, U>: ParseEncodable where T: ParseEncodable, U: Sendable {
let requests: [API.Command<T, U>]
var transaction: Bool
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,26 +396,26 @@ public extension ParseUser {
}

internal func linkCommand() async throws -> API.Command<Self, Self> {
var mutableSelf = self.anonymous.strip(self)
let strippedUser = self.anonymous.strip(self)
if let current = try? await Self.current() {
guard current.hasSameObjectId(as: mutableSelf) else {
guard current.hasSameObjectId(as: strippedUser) else {
let error = ParseError(code: .otherCause,
message: "Cannot signup a user with a different objectId than the current user")
throw error
}
}
return API.Command<Self, Self>(method: .PUT,
path: endpoint,
body: mutableSelf) { (data) -> Self in
body: strippedUser) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data)
mutableSelf = user.apply(to: mutableSelf)
let updatedUser = user.apply(to: strippedUser)
if let sessionToken = user.sessionToken {
await Self.setCurrentContainer(.init(currentUser: mutableSelf,
await Self.setCurrentContainer(.init(currentUser: updatedUser,
sessionToken: sessionToken))
} else {
try await Self.setCurrent(mutableSelf)
try await Self.setCurrent(updatedUser)
}
return mutableSelf
return updatedUser
}
}

Expand All @@ -431,13 +431,14 @@ public extension ParseUser {
}
body.authData = currentAuthData
}
let updatedBody = body

return API.Command<SignupLoginBody, Self>(method: .PUT,
path: endpoint,
body: body) { (data) -> Self in
body: updatedBody) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data)
var currentUser = user.apply(to: currentStrippedUser)
currentUser.authData = body.authData
currentUser.authData = updatedBody.authData
if let sessionToken = user.sessionToken {
await Self.setCurrentContainer(.init(currentUser: currentUser,
sessionToken: sessionToken))
Expand Down
11 changes: 11 additions & 0 deletions Sources/ParseSwift/Extensions/InputStream.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// InputStream.swift
// ParseSwift
//
// Created by Corey Baker on 7/10/24.
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
//

import Foundation

extension InputStream: @unchecked Sendable {}
9 changes: 5 additions & 4 deletions Sources/ParseSwift/Objects/ParseInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,9 @@ extension ParseInstallation {
let acl = try? await ParseACL.defaultACL() {
object.ACL = acl
}
let mapper = { (data) -> Self in
try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: object)
let updatedObject = object
let mapper = { @Sendable (data) -> Self in
try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: updatedObject)
}
return API.Command<Self, Self>(method: .POST,
path: try await endpoint(.POST),
Expand All @@ -761,7 +762,7 @@ extension ParseInstallation {
throw ParseError(code: .missingObjectId,
message: "objectId must not be nil")
}
let mapper = { (data: Data) -> Self in
let mapper = { @Sendable (data: Data) -> Self in
var updatedObject = self
updatedObject.originalData = nil
updatedObject = try ParseCoding.jsonDecoder().decode(ReplaceResponse.self,
Expand All @@ -786,7 +787,7 @@ extension ParseInstallation {
throw ParseError(code: .missingObjectId,
message: "objectId must not be nil")
}
let mapper = { (data: Data) -> Self in
let mapper = { @Sendable (data: Data) -> Self in
var updatedObject = self
updatedObject.originalData = nil
updatedObject = try ParseCoding.jsonDecoder().decode(UpdateResponse.self,
Expand Down
9 changes: 5 additions & 4 deletions Sources/ParseSwift/Objects/ParseUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1216,13 +1216,14 @@ extension ParseUser {
let acl = try? await ParseACL.defaultACL() {
user.ACL = acl
}
let mapper = { (data) -> Self in
let updatedUser = user
let mapper = { @Sendable (data) -> Self in
try ParseCoding
.jsonDecoder()
.decode(
CreateResponse.self,
from: data
).apply(to: user)
).apply(to: updatedUser)
}
let path = try await endpoint(.POST)
let command = API.Command<Self, Self>(
Expand All @@ -1246,7 +1247,7 @@ extension ParseUser {
mutableSelf.email = nil
}
}
let mapper = { (data: Data) -> Self in
let mapper = { @Sendable (data: Data) -> Self in
var updatedUser = self
updatedUser.originalData = nil
let userResponse = try ParseCoding
Expand Down Expand Up @@ -1301,7 +1302,7 @@ extension ParseUser {
mutableSelf.email = nil
}
}
let mapper = { (data: Data) -> Self in
let mapper = { @Sendable (data: Data) -> Self in
var updatedUser = self
updatedUser.originalData = nil
let userResponse = try ParseCoding
Expand Down
4 changes: 2 additions & 2 deletions Sources/ParseSwift/ParseConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

enum ParseConstants {
static let sdk = "swift"
static let version = "5.9.3"
static let version = "5.10.0"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down Expand Up @@ -44,7 +44,7 @@ enum Method: String {
/**
The types of Parse Hook Triggers available.
*/
public enum ParseHookTriggerType: String, Codable {
public enum ParseHookTriggerType: String, Codable, Sendable {
/// Occurs before login of a `ParseUser`.
case beforeLogin
/// Occurs after login of a `ParseUser`.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Protocols/ParseEncodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Foundation
Types that conform to **ParseEncodable** should be encoded by the
`ParseEncoder` when necessary.
*/
public protocol ParseEncodable: Encodable {}
public protocol ParseEncodable: Encodable, Sendable {}

// MARK: CustomDebugStringConvertible
extension ParseEncodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Protocols/ParseHookFunctionable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public extension ParseHookFunctionable {
}

/// A type of request for Parse Hook Functions.
public struct FunctionRequest: Encodable {
public struct FunctionRequest: Encodable, Sendable {
let functionName: String
let url: URL?

Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Protocols/ParseHookParametable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ import Foundation
Conforming to `ParseHookParametable` allows types that can be created
to decode parameters in `ParseHookFunctionRequest`'s.
*/
public protocol ParseHookParametable: Codable, Equatable {}
public protocol ParseHookParametable: Codable, Equatable, Sendable {}
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Protocols/ParseHookTriggerable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public extension ParseHookTriggerable {
}

/// A type of request for Parse Hook Triggers.
public struct TriggerRequest: Encodable {
public struct TriggerRequest: Encodable, Sendable {
let className: String
let trigger: ParseHookTriggerType
let url: URL?
Expand Down
1 change: 1 addition & 0 deletions Sources/ParseSwift/Protocols/ParseTypeable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Foundation
A special type that is considered a Parse type.
*/
public protocol ParseTypeable: Codable,
Sendable,
Equatable,
CustomDebugStringConvertible,
CustomStringConvertible {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

/// Represents all supported Parse operation commands.
public enum ParseOperationCommand: String, Codable {
public enum ParseOperationCommand: String, Codable, Sendable {
/// The add command.
case add = "Add"
/// The add relation command.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Types/ParseACL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct ParseACL: ParseTypeable,
/**
An enum specifying read and write access controls.
*/
public enum Access: String, Codable, CodingKey {
public enum Access: String, Codable, Sendable, CodingKey {
/// Read access control.
case read
/// Write access control.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Types/ParseField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public struct ParseField: ParseTypeable {
var targetClass: String?

/// Field types available in `ParseSchema`.
public enum FieldType: String, Codable {
public enum FieldType: String, Codable, Sendable {
/// A string type.
case string = "String"
/// A number type.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Types/ParseHookResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Foundation
Build a response after processing a `ParseHookFunctionRequest`
or `ParseHookTriggerRequest`.
*/
public struct ParseHookResponse<R: Codable & Equatable>: ParseTypeable {
public struct ParseHookResponse<R: Codable & Equatable & Sendable>: ParseTypeable {
/// The data to return in the response.
public var success: R?
/// An object with a Parse code and message.
Expand Down
Loading

0 comments on commit 10ec67c

Please sign in to comment.