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

Firestore Swift Cpp Experiment #13956

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion FirebaseCombineSwift.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ for internal testing only. It should not be published.

s.pod_target_xcconfig = {
'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"',
'SWIFT_OBJC_INTEROP_MODE' => 'objcxx',
}

s.test_spec 'unit' do |unit_tests|
Expand All @@ -81,7 +82,8 @@ for internal testing only. It should not be published.
unit_tests.exclude_files = 'FirebaseCombineSwift/Tests/Unit/**/*Template.swift'
unit_tests.requires_app_host = true
unit_tests.pod_target_xcconfig = {
'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/FirebaseCombineSwift/Tests/Unit/FirebaseCombine-unit-Bridging-Header.h'
'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/FirebaseCombineSwift/Tests/Unit/FirebaseCombine-unit-Bridging-Header.h',
'SWIFT_OBJC_INTEROP_MODE' => 'objcxx',
}
unit_tests.dependency 'OCMock'
unit_tests.dependency 'FirebaseAuthTestingSupport'
Expand Down
9 changes: 9 additions & 0 deletions FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@
NS_ASSUME_NONNULL_BEGIN

/** Returns the current version of Firebase. */

#ifdef __cplusplus
extern "C" {
#endif

NS_SWIFT_NAME(FirebaseVersion())
NSString* FIRFirebaseVersion(void);

#ifdef __cplusplus
}
#endif

NS_ASSUME_NONNULL_END
6 changes: 6 additions & 0 deletions FirebaseFirestore.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
'FirebaseFirestoreInternal/**/*.[mh]',
'Firestore/Swift/Source/**/*.swift',
]

s.pod_target_xcconfig = {
# Enables C++ <-> Swift interop (by default it's only C)
"SWIFT_OBJC_INTEROP_MODE" => "objcxx",
}

s.resource_bundles = {
"#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy'
}
Expand Down
6 changes: 5 additions & 1 deletion FirebaseFirestoreInternal.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
# Header files that constitute the interface to this module. Only Objective-C
# headers belong here, since FirebaseFirestore is primarily an Objective-C
# framework.
s.public_header_files = 'Firestore/Source/Public/FirebaseFirestore/*.h'
s.public_header_files = [
'Firestore/Source/Public/FirebaseFirestore/*.h',
'Firestore/core/interfaceForSwift/api/*.h'
]

# source_files contains most of the header and source files for the project.
# This includes files named in `public_header_files`.
Expand All @@ -52,6 +55,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
'Firestore/core/include/**/*.{cc,mm}',
'Firestore/core/src/**/*.{cc,mm}',
'FirebaseAuth/Interop/**/*.h',
'Firestore/core/interfaceForSwift/**/*.{cc,h}',
]

# Internal headers that aren't necessarily globally unique. Most C++ internal
Expand Down
481 changes: 250 additions & 231 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Firestore/Example/Tests/API/FIRAggregateQueryUnitTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ @interface FIRAggregateQueryUnitTests : XCTestCase
@implementation FIRAggregateQueryUnitTests

- (void)testEquals {
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().wrapped;
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().cppFirestorePtr;
FIRAggregateQuery *queryFoo =
[[FIRQuery alloc] initWithQuery:Query("foo") firestore:firestore].count;
FIRAggregateQuery *queryFooDup =
Expand Down
2 changes: 1 addition & 1 deletion Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ - (void)testIncludeMetadataChanges {
DocumentViewChange(doc2New, DocumentViewChange::Type::Modified),
};

std::shared_ptr<Firestore> firestore = FSTTestFirestore().wrapped;
std::shared_ptr<Firestore> firestore = FSTTestFirestore().cppFirestorePtr;
core::Query query = Query("foo");
ViewSnapshot viewSnapshot(query, newDocuments, oldDocuments, std::move(documentChanges),
/*mutated_keys=*/DocumentKeySet(),
Expand Down
4 changes: 2 additions & 2 deletions Firestore/Example/Tests/API/FIRQueryUnitTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ @interface FIRQueryUnitTests : XCTestCase
@implementation FIRQueryUnitTests

- (void)testEquals {
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().wrapped;
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().cppFirestorePtr;
FIRQuery *queryFoo = [[FIRQuery alloc] initWithQuery:Query("foo") firestore:firestore];
FIRQuery *queryFooDup = [[FIRQuery alloc] initWithQuery:Query("foo") firestore:firestore];
FIRQuery *queryBar = [[FIRQuery alloc] initWithQuery:Query("bar") firestore:firestore];
Expand All @@ -58,7 +58,7 @@ - (void)testEquals {
}

- (void)testFilteringWithPredicate {
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().wrapped;
std::shared_ptr<api::Firestore> firestore = FSTTestFirestore().cppFirestorePtr;
FIRQuery *query = [[FIRQuery alloc] initWithQuery:Query("foo") firestore:firestore];
FIRQuery *query1 = [query queryWhereField:@"f" isLessThanOrEqualTo:@1];
FIRQuery *query2 = [query queryFilteredUsingPredicate:[NSPredicate predicateWithFormat:@"f<=1"]];
Expand Down
6 changes: 3 additions & 3 deletions Firestore/Example/Tests/API/FSTAPIHelpers.mm
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@

FIRCollectionReference *FSTTestCollectionRef(const char *path) {
return [[FIRCollectionReference alloc] initWithPath:Resource(path)
firestore:FSTTestFirestore().wrapped];
firestore:FSTTestFirestore().cppFirestorePtr];
}

FIRDocumentReference *FSTTestDocRef(const char *path) {
return [[FIRDocumentReference alloc] initWithPath:Resource(path)
firestore:FSTTestFirestore().wrapped];
firestore:FSTTestFirestore().cppFirestorePtr];
}

/** A convenience method for creating a query snapshots for tests. */
Expand Down Expand Up @@ -157,7 +157,7 @@
/*sync_state_changed=*/true,
/*excludes_metadata_changes=*/false,
static_cast<bool>(hasCachedResults)};
return [[FIRQuerySnapshot alloc] initWithFirestore:FSTTestFirestore().wrapped
return [[FIRQuerySnapshot alloc] initWithFirestore:FSTTestFirestore().cppFirestorePtr
originalQuery:Query(path)
snapshot:std::move(viewSnapshot)
metadata:std::move(metadata)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1523,7 +1523,7 @@ - (void)testAppDeleteLeadsToFirestoreTermination {

[self deleteApp:app];

XCTAssertTrue(firestore.wrapped->client()->is_terminated());
XCTAssertTrue(firestore.cppFirestorePtr->client()->is_terminated());
}

// Ensures b/172958106 doesn't regress.
Expand Down
2 changes: 1 addition & 1 deletion Firestore/Source/API/FIRAggregateQuerySnapshot.mm
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ - (id)valueForAggregateField:(FIRAggregateField *)aggregateField {
[aggregateField name], path);
}
FSTUserDataWriter *dataWriter =
[[FSTUserDataWriter alloc] initWithFirestore:_query.query.firestore.wrapped
[[FSTUserDataWriter alloc] initWithFirestore:_query.query.firestore.cppFirestorePtr
serverTimestampBehavior:serverTimestampBehavior];
return [dataWriter convertedValue:*fieldValue];
}
Expand Down
66 changes: 66 additions & 0 deletions Firestore/Source/API/FIRCallbackWrapper.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "FIRCallbackWrapper.h"

#include <memory>
#include <utility>
#include <vector>

#include "Firestore/core/interfaceForSwift/api/pipeline.h"
#include "Firestore/core/interfaceForSwift/api/pipeline_result.h"
#include "Firestore/core/src/core/event_listener.h"
#include "Firestore/core/src/util/error_apple.h"
#include "Firestore/core/src/util/statusor.h"

using firebase::firestore::api::PipelineResult;
using firebase::firestore::api::PipelineSnapshotListener;
using firebase::firestore::core::EventListener;
using firebase::firestore::util::MakeNSError;
using firebase::firestore::util::StatusOr;

@implementation FIRCallbackWrapper

+ (PipelineSnapshotListener)
wrapPipelineCallback:(std::shared_ptr<api::Firestore>)firestore
completion:(void (^)(std::shared_ptr<std::vector<PipelineResult>> result,
NSError *_Nullable error))completion {
class Converter : public EventListener<std::vector<PipelineResult>> {
public:
explicit Converter(std::shared_ptr<api::Firestore> firestore, PipelineBlock completion)
: firestore_(firestore), completion_(completion) {
}

void OnEvent(StatusOr<std::vector<PipelineResult>> maybe_snapshot) override {
if (maybe_snapshot.ok()) {
completion_(
std::make_shared<std::vector<PipelineResult>>(
std::initializer_list<PipelineResult>{PipelineResult::GetTestResult(firestore_)}),
nullptr);
} else {
completion_(nullptr, MakeNSError(maybe_snapshot.status()));
}
}

private:
std::shared_ptr<api::Firestore> firestore_;
PipelineBlock completion_;
};

return absl::make_unique<Converter>(firestore, completion);
}

@end
6 changes: 3 additions & 3 deletions Firestore/Source/API/FIRDocumentSnapshot.mm
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ - (instancetype)initWithFirestore:(FIRFirestore *)firestore
metadata:(SnapshotMetadata)metadata {
DocumentSnapshot wrapped;
if (document.has_value()) {
wrapped =
DocumentSnapshot::FromDocument(firestore.wrapped, document.value(), std::move(metadata));
wrapped = DocumentSnapshot::FromDocument(firestore.cppFirestorePtr, document.value(),
std::move(metadata));
} else {
wrapped = DocumentSnapshot::FromNoDocument(firestore.wrapped, std::move(documentKey),
wrapped = DocumentSnapshot::FromNoDocument(firestore.cppFirestorePtr, std::move(documentKey),
std::move(metadata));
}
_serializer.reset(new Serializer(firestore.databaseID));
Expand Down
2 changes: 0 additions & 2 deletions Firestore/Source/API/FIRFirestore+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ NS_ASSUME_NONNULL_BEGIN

- (const std::shared_ptr<firebase::firestore::util::AsyncQueue> &)workerQueue;

@property(nonatomic, assign, readonly) std::shared_ptr<api::Firestore> wrapped;

@property(nonatomic, assign, readonly) const model::DatabaseId &databaseID;
@property(nonatomic, strong, readonly) FSTUserDataReader *dataReader;

Expand Down
2 changes: 1 addition & 1 deletion Firestore/Source/API/FIRFirestore.mm
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ - (void)getQueryNamed:(NSString *)name completion:(void (^)(FIRQuery *_Nullable

@implementation FIRFirestore (Internal)

- (std::shared_ptr<Firestore>)wrapped {
- (std::shared_ptr<Firestore>)cppFirestorePtr {
return _firestore;
}

Expand Down
2 changes: 1 addition & 1 deletion Firestore/Source/API/FIRQuery.mm
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ - (void)getDocumentsWithSource:(FIRFirestoreSource)publicSource
- (id<FIRListenerRegistration>)addSnapshotListenerInternalWithOptions:(ListenOptions)internalOptions
listener:
(FIRQuerySnapshotBlock)listener {
std::shared_ptr<Firestore> firestore = self.firestore.wrapped;
std::shared_ptr<Firestore> firestore = self.firestore.cppFirestorePtr;
const core::Query &query = self.query;

// Convert from ViewSnapshots to QuerySnapshots.
Expand Down
64 changes: 64 additions & 0 deletions Firestore/Source/Public/FirebaseFirestore/FIRCallbackWrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Foundation/Foundation.h>
#include <memory>
#include <vector>

namespace firebase {
namespace firestore {
namespace api {
class Firestore;
class PipelineResult;
} // namespace api

namespace core {
template <typename T>
class EventListener;
} // namespace core

} // namespace firestore
} // namespace firebase

namespace api = firebase::firestore::api;
namespace core = firebase::firestore::core;

NS_ASSUME_NONNULL_BEGIN

typedef void (^PipelineBlock)(std::shared_ptr<std::vector<api::PipelineResult>> result,
NSError *_Nullable error)
NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");

typedef std::shared_ptr<std::vector<api::PipelineResult>> PipelineResultVectorPtr;

NS_SWIFT_SENDABLE
NS_SWIFT_NAME(CallbackWrapper)
@interface FIRCallbackWrapper : NSObject

// Note: Marking callbacks in callback-based APIs as `Sendable` can help prevent crashes when they
// are invoked on a different thread than the one they were originally defined in. If this callback
// is expected to be called on a different thread, it should be marked as `Sendable` to ensure
// thread safety.
+ (std::unique_ptr<core::EventListener<std::vector<api::PipelineResult>>>)
wrapPipelineCallback:(std::shared_ptr<api::Firestore>)firestore
completion:(void (^NS_SWIFT_SENDABLE)(
std::shared_ptr<std::vector<api::PipelineResult>> result,
NSError *_Nullable error))completion
NS_SWIFT_NAME(wrapPipelineCallback(firestore:completion:));

@end

NS_ASSUME_NONNULL_END
13 changes: 13 additions & 0 deletions Firestore/Source/Public/FirebaseFirestore/FIRFirestore.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#import <Foundation/Foundation.h>
#include <memory>

#import "FIRListenerRegistration.h"

Expand All @@ -30,6 +31,16 @@
@class FIRWriteBatch;
@class FIRPersistentCacheIndexManager;

namespace firebase {
namespace firestore {
namespace api {
class Firestore;
} // namespace api
} // namespace firestore
} // namespace firebase

namespace cppApi = firebase::firestore::api;

NS_ASSUME_NONNULL_BEGIN

/**
Expand Down Expand Up @@ -91,6 +102,8 @@ NS_SWIFT_NAME(Firestore)
*/
+ (instancetype)firestoreForDatabase:(NSString *)database NS_SWIFT_NAME(firestore(database:));

@property(nonatomic, assign, readonly) std::shared_ptr<cppApi::Firestore> cppFirestorePtr;

/**
* Custom settings used to configure this `Firestore` object.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import "FIRAggregateQuery.h"
#import "FIRAggregateQuerySnapshot.h"
#import "FIRAggregateSource.h"
#import "FIRCallbackWrapper.h"
#import "FIRCollectionReference.h"
#import "FIRDocumentChange.h"
#import "FIRDocumentReference.h"
Expand Down
5 changes: 5 additions & 0 deletions Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#if SWIFT_PACKAGE
import FirebaseFirestoreCpp
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
Expand Down Expand Up @@ -115,4 +116,8 @@
}
}
}

func pipeline() -> PipelineSource {
return PipelineSource(firebase.firestore.api.FirestorePipeline.pipeline(cppFirestorePtr))

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / platforms (catalyst)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-15, Xcode_16, spm)

cannot find 'cppFirestorePtr' in scope

Check failure on line 121 in Firestore/Swift/Source/AsyncAwait/Firestore+AsyncAwait.swift

View workflow job for this annotation

GitHub Actions / swift-build-run (macos-14, Xcode_15.3, spm)

cannot find 'cppFirestorePtr' in scope
}
}
Loading
Loading