Skip to content
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
16 changes: 8 additions & 8 deletions FirebaseAuth/Sources/Swift/ActionCode/ActionCodeSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,22 @@ import Foundation
private extension ActionCodeSettings {
/// Checked Sendable implementation of `ActionCodeSettings`.
final class SendableActionCodeSettings: Sendable {
let url = FIRAllocatedUnfairLock<URL?>(initialState: nil)
let url = UnfairLock<URL?>(nil)

let handleCodeInApp = FIRAllocatedUnfairLock<Bool>(initialState: false)
let handleCodeInApp = UnfairLock<Bool>(false)

let iOSBundleID: FIRAllocatedUnfairLock<String?>
let iOSBundleID: UnfairLock<String?>

let androidPackageName = FIRAllocatedUnfairLock<String?>(initialState: nil)
let androidPackageName = UnfairLock<String?>(nil)

let androidMinimumVersion = FIRAllocatedUnfairLock<String?>(initialState: nil)
let androidMinimumVersion = UnfairLock<String?>(nil)

let androidInstallIfNotAvailable = FIRAllocatedUnfairLock<Bool>(initialState: false)
let androidInstallIfNotAvailable = UnfairLock<Bool>(false)

let linkDomain = FIRAllocatedUnfairLock<String?>(initialState: nil)
let linkDomain = UnfairLock<String?>(nil)

init() {
iOSBundleID = FIRAllocatedUnfairLock<String?>(initialState: Bundle.main.bundleIdentifier)
iOSBundleID = UnfairLock<String?>(Bundle.main.bundleIdentifier)
}

func setAndroidPackageName(_ androidPackageName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ final class AuthKeychainServices: Sendable {
/// been deleted.
///
/// This dictionary is to avoid unnecessary keychain operations against legacy items.
private let legacyEntryDeletedForKey = FIRAllocatedUnfairLock<Set<String>>(initialState: [])
private let legacyEntryDeletedForKey = UnfairLock<Set<String>>([])

func data(forKey key: String) throws -> Data? {
if let data = try getItemLegacy(query: genericPasswordQuery(key: key)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ final class SecureTokenService: NSObject, NSSecureCoding, Sendable {
set { _requestConfiguration.withLock { $0 = newValue } }
}

let _requestConfiguration: FIRAllocatedUnfairLock<AuthRequestConfiguration?>
let _requestConfiguration: UnfairLock<AuthRequestConfiguration?>

/// The cached access token.
///
Expand All @@ -140,7 +140,7 @@ final class SecureTokenService: NSObject, NSSecureCoding, Sendable {
set { _accessToken.withLock { $0 = newValue } }
}

private let _accessToken: FIRAllocatedUnfairLock<String>
private let _accessToken: UnfairLock<String>

/// The refresh token for the user, or `nil` if the user has yet completed sign-in flow.
///
Expand All @@ -150,15 +150,15 @@ final class SecureTokenService: NSObject, NSSecureCoding, Sendable {
set { _refreshToken.withLock { $0 = newValue } }
}

private let _refreshToken: FIRAllocatedUnfairLock<String?>
private let _refreshToken: UnfairLock<String?>

/// The expiration date of the cached access token.
var accessTokenExpirationDate: Date? {
get { _accessTokenExpirationDate.withLock { $0 } }
set { _accessTokenExpirationDate.withLock { $0 = newValue } }
}

private let _accessTokenExpirationDate: FIRAllocatedUnfairLock<Date?>
private let _accessTokenExpirationDate: UnfairLock<Date?>

/// Creates a `SecureTokenService` with access and refresh tokens.
/// - Parameter requestConfiguration: The configuration for making requests to server.
Expand All @@ -170,10 +170,10 @@ final class SecureTokenService: NSObject, NSSecureCoding, Sendable {
accessTokenExpirationDate: Date?,
refreshToken: String) {
internalService = SecureTokenServiceInternal()
_requestConfiguration = FIRAllocatedUnfairLock(initialState: requestConfiguration)
_accessToken = FIRAllocatedUnfairLock(initialState: accessToken)
_accessTokenExpirationDate = FIRAllocatedUnfairLock(initialState: accessTokenExpirationDate)
_refreshToken = FIRAllocatedUnfairLock(initialState: refreshToken)
_requestConfiguration = UnfairLock(requestConfiguration)
_accessToken = UnfairLock(accessToken)
_accessTokenExpirationDate = UnfairLock(accessTokenExpirationDate)
_refreshToken = UnfairLock(refreshToken)
}

/// Fetch a fresh ephemeral access token for the ID associated with this instance. The token
Expand Down
8 changes: 4 additions & 4 deletions FirebaseAuth/Tests/Unit/AuthAPNSTokenManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
func testCallback() throws {
let expectation = self.expectation(description: #function)
XCTAssertFalse(fakeApplication!.registerCalled)
let firstCallbackCalled = FIRAllocatedUnfairLock(initialState: false)
let firstCallbackCalled = UnfairLock(false)
let manager = try XCTUnwrap(manager)
manager.getTokenInternal { result in
firstCallbackCalled.withLock { $0 = true }
Expand All @@ -77,7 +77,7 @@
XCTAssertFalse(firstCallbackCalled.value())

// Add second callback, which is yet to be called either.
let secondCallbackCalled = FIRAllocatedUnfairLock(initialState: false)
let secondCallbackCalled = UnfairLock(false)
manager.getTokenInternal { result in
secondCallbackCalled.withLock { $0 = true }
switch result {
Expand All @@ -104,7 +104,7 @@
XCTAssertEqual(manager.token?.type, .sandbox)

// Add third callback, which should be called back immediately.
let thirdCallbackCalled = FIRAllocatedUnfairLock(initialState: false)
let thirdCallbackCalled = UnfairLock(false)
manager.getTokenInternal { result in
thirdCallbackCalled.withLock { $0 = true }
switch result {
Expand Down Expand Up @@ -178,7 +178,7 @@
XCTAssertGreaterThan(try XCTUnwrap(manager.timeout), 0)

// Add callback to cancel.
let callbackCalled = FIRAllocatedUnfairLock(initialState: false)
let callbackCalled = UnfairLock(false)
manager.getTokenInternal { result in
switch result {
case let .success(token):
Expand Down
4 changes: 2 additions & 2 deletions FirebaseAuth/Tests/Unit/Fakes/FakeAuthKeychainStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import XCTest
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
final class FakeAuthKeychainStorage: AuthKeychainStorage {
// Fake Keychain. It's a dictionary, keyed by service name, for each key-value store dictionary
private let fakeKeychain = FIRAllocatedUnfairLock<[String: [String: Any]]>(initialState: [:])
private let fakeKeychain = UnfairLock<[String: [String: Any]]>([:])

private let fakeLegacyKeychain = FIRAllocatedUnfairLock<[String: Any]>(initialState: [:])
private let fakeLegacyKeychain = UnfairLock<[String: Any]>([:])

func get(query: [String: Any], result: inout AnyObject?) -> OSStatus {
if let service = queryService(query) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol {
// MARK: - Instance Management

/// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs.
private static let cachedInstances: FIRAllocatedUnfairLock<
private static let cachedInstances: UnfairLock<
[String: WeakContainer<HeartbeatStorage>]
> = FIRAllocatedUnfairLock(initialState: [:])
> = UnfairLock([:])

/// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise,
/// makes a new instance with the given `id`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ import Foundation
struct WeakContainer<Object: AnyObject> {
weak var object: Object?
}

extension WeakContainer: Sendable where Object: Sendable {}
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,54 @@
// limitations under the License.

import Foundation
import os.lock
private import os.lock

/// A reference wrapper around `os_unfair_lock`. Replace this class with
/// `OSAllocatedUnfairLock` once we support only iOS 16+. For an explanation
/// on why this is necessary, see the docs:
/// https://developer.apple.com/documentation/os/osallocatedunfairlock
public final class FIRAllocatedUnfairLock<State>: @unchecked Sendable {
public final class UnfairLock<Value>: @unchecked Sendable {
private var lockPointer: UnsafeMutablePointer<os_unfair_lock>
private var state: State
private var _value: Value

public init(initialState: sending State) {
public init(_ value: consuming sending Value) {
lockPointer = UnsafeMutablePointer<os_unfair_lock>
.allocate(capacity: 1)
lockPointer.initialize(to: os_unfair_lock())
state = initialState
_value = value
}

public convenience init() where State == Void {
self.init(initialState: ())
}

public func lock() {
os_unfair_lock_lock(lockPointer)
}

public func unlock() {
os_unfair_lock_unlock(lockPointer)
deinit {
lockPointer.deallocate()
}

public func value() -> State {
public func value() -> Value {
lock()
defer { unlock() }
return state
return _value
}

@discardableResult
public func withLock<R>(_ body: (inout State) throws -> R) rethrows -> R {
let value: R
public borrowing func withLock<Result>(_ body: (inout sending Value) throws
-> sending Result) rethrows -> sending Result {
lock()
defer { unlock() }
value = try body(&state)
return value
return try body(&_value)
}

@discardableResult
public func withLock<R>(_ body: () throws -> R) rethrows -> R {
let value: R
public borrowing func withLock<Result>(_ body: (inout sending Value) -> sending Result)
-> sending Result {
lock()
defer { unlock() }
value = try body()
return value
return body(&_value)
}

deinit {
lockPointer.deallocate()
private func lock() {
os_unfair_lock_lock(lockPointer)
}

private func unlock() {
os_unfair_lock_unlock(lockPointer)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ class HeartbeatStorageTests: XCTestCase {
final class WeakRefs: @unchecked Sendable {
// Lock is used to synchronize `weakRefs` during concurrent access.
private(set) var weakRefs =
FIRAllocatedUnfairLock<[WeakContainer<HeartbeatStorage>]>(initialState: [])
UnfairLock<[WeakContainer<HeartbeatStorage>]>([])

func append(_ weakRef: WeakContainer<HeartbeatStorage>) {
weakRefs.withLock {
Expand Down
6 changes: 3 additions & 3 deletions FirebaseFunctions/Sources/Functions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@

/// A map of active instances, grouped by app. Keys are FirebaseApp names and values are arrays
/// containing all instances of Functions associated with the given app.
private static let instances = FIRAllocatedUnfairLock<[String: [Functions]]>(initialState: [:])
private static let instances = UnfairLock<[String: [Functions]]>([:])

/// The custom domain to use for all functions references (optional).
let customDomain: String?

/// The region to use for all function references.
let region: String

private let _emulatorOrigin: FIRAllocatedUnfairLock<String?>
private let _emulatorOrigin: UnfairLock<String?>

// MARK: - Public APIs

Expand Down Expand Up @@ -341,7 +341,7 @@
self.projectID = projectID
self.region = region
self.customDomain = customDomain
_emulatorOrigin = FIRAllocatedUnfairLock(initialState: nil)
_emulatorOrigin = UnfairLock(nil)
contextProvider = FunctionsContextProvider(auth: auth,
messaging: messaging,
appCheck: appCheck)
Expand Down Expand Up @@ -404,7 +404,7 @@
let rawData = try await fetcher.beginFetch()
return try callableResult(fromResponseData: rawData, endpointURL: url)
} catch {
throw processedError(fromResponseError: error, endpointURL: url)

Check failure on line 407 in FirebaseFunctions/Sources/Functions.swift

View workflow job for this annotation

GitHub Actions / spm-integration (FirebaseFunctionsIntegration) / spm (macos-15, Xcode_16.4, iOS)

testCallAsFunctionAsync, failed: caught error: "FunctionsError(code: FirebaseFunctions.FunctionsErrorCode, errorUserInfo: ["NSLocalizedDescription": "INTERNAL"])"
}
}

Expand Down
2 changes: 1 addition & 1 deletion FirebaseFunctions/Sources/HTTPSCallable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public final class HTTPSCallable: NSObject, Sendable {

private let options: HTTPSCallableOptions?

private let _timeoutInterval: AtomicBox<TimeInterval> = .init(70)
private let _timeoutInterval: UnfairLock<TimeInterval> = .init(70)

// MARK: - Public Properties

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ extension InstallationsProtocol {
// TODO(ncooke3): Convert o async await ahead of Firebase 12.

func installationID(completion: @escaping (Result<(String, String), Error>) -> Void) {
let authTokenComplete = FIRAllocatedUnfairLock<String>(initialState: "")
let installationComplete = FIRAllocatedUnfairLock<String?>(initialState: nil)
let errorComplete = FIRAllocatedUnfairLock<Error?>(initialState: nil)
let authTokenComplete = UnfairLock<String>("")
let installationComplete = UnfairLock<String?>(nil)
let errorComplete = UnfairLock<Error?>(nil)

let workingGroup = DispatchGroup()

Expand Down
2 changes: 1 addition & 1 deletion FirebaseSessions/Sources/Public/SessionsDependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private import FirebaseCoreInternal
@objc(FIRSessionsDependencies)
public class SessionsDependencies: NSObject {
private static let _dependencies =
FIRAllocatedUnfairLock<Set<SessionsSubscriberName>>(initialState: Set())
UnfairLock<Set<SessionsSubscriberName>>(Set())

static var dependencies: Set<SessionsSubscriberName> {
_dependencies.value()
Expand Down
4 changes: 2 additions & 2 deletions FirebaseSessions/Sources/Public/SessionsSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public protocol SessionsSubscriber: Sendable {
/// Session Payload is a container for Session Data passed to Subscribers
/// whenever the Session changes
@objc(FIRSessionDetails)
public class SessionDetails: NSObject {
@objc public var sessionId: String?
public final class SessionDetails: NSObject, Sendable {
@objc public let sessionId: String?

public init(sessionId: String?) {
self.sessionId = sessionId
Expand Down
4 changes: 2 additions & 2 deletions FirebaseSessions/Sources/Settings/RemoteSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class RemoteSettings: SettingsProvider, Sendable {
private static let flagSessionsCache = "app_quality"
private let appInfo: ApplicationInfoProtocol
private let downloader: SettingsDownloadClient
private let cache: FIRAllocatedUnfairLock<SettingsCacheClient>
private let cache: UnfairLock<SettingsCacheClient>

private var sessionsCache: [String: Any] {
cache.withLock { cache in
Expand All @@ -41,7 +41,7 @@ final class RemoteSettings: SettingsProvider, Sendable {
downloader: SettingsDownloadClient,
cache: SettingsCacheClient = SettingsCache()) {
self.appInfo = appInfo
self.cache = FIRAllocatedUnfairLock(initialState: cache)
self.cache = UnfairLock(cache)
self.downloader = downloader
}

Expand Down
6 changes: 2 additions & 4 deletions FirebaseSessions/Tests/Unit/Mocks/MockSubscriber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ final class MockSubscriber: SessionsSubscriber, Sendable {
set { _isDataCollectionEnabled.withLock { $0 = newValue } }
}

private let _sessionThatChanged = FIRAllocatedUnfairLock<FirebaseSessions.SessionDetails?>(
initialState: nil
)
private let _isDataCollectionEnabled = FIRAllocatedUnfairLock<Bool>(initialState: true)
private let _sessionThatChanged = UnfairLock<FirebaseSessions.SessionDetails?>(nil)
private let _isDataCollectionEnabled = UnfairLock<Bool>(true)

init(name: SessionsSubscriberName) {
sessionsSubscriberName = name
Expand Down
Loading