Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Mark ParseObject and related types as Sendable #174

Merged
merged 4 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
}

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)

Check warning on line 416 in Sources/ParseSwift/Authentication/Protocols/ParseAuthentication.swift

View check run for this annotation

Codecov / codecov/patch

Sources/ParseSwift/Authentication/Protocols/ParseAuthentication.swift#L416

Added line #L416 was not covered by tests
}
return mutableSelf
return updatedUser
}
}

Expand All @@ -431,13 +431,14 @@
}
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
Loading