blob: 1fbf98eb77372a8841595e5242f165487ae53ec8 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/common/credential_provider/credential_store_util.h"
#import "base/barrier_callback.h"
#import "ios/chrome/common/credential_provider/credential_store.h"
namespace credential_store_util {
namespace {
// Wrapper around an NSArray of Credential, so it can be stored in a C++
// collection. This is useful for interacting with Callbacks.
struct CredentialFetchResult {
NSArray<id<Credential>>* credentials;
};
// Given a list of lists of credentials, returns a single list containing the
// unique elements.
NSArray<id<Credential>>* Merge(
const std::vector<CredentialFetchResult>& results) {
// Compute total count so we can reserve space.
NSUInteger total_count = 0;
for (const CredentialFetchResult& result : results) {
total_count += result.credentials.count;
}
NSMutableArray<id<Credential>>* merged_result =
[[NSMutableArray alloc] initWithCapacity:total_count];
for (const CredentialFetchResult& result : results) {
[merged_result addObjectsFromArray:result.credentials];
}
return merged_result;
}
} // namespace
void ReadFromMultipleCredentialStoresAsync(
NSArray<id<CredentialStore>>* stores,
base::OnceCallback<void(NSArray<id<Credential>>*)> completion) {
// BarrierCallback collects the output of each individual read, and only
// once all results are accumulated will it merge the results and finally
// invoke `completion`. It is thread-safe, but `completion` will be run
// synchronously on the thread where the last read occurred.
auto accumulator = base::BarrierCallback<CredentialFetchResult>(
stores.count, base::BindOnce(&Merge).Then(std::move(completion)));
for (id<CredentialStore> store in stores) {
// Create one single-use instance (copy) of `accumulator` per store/block.
// These instances share state. Use __block to prevent a needless second
// copy (once on this line, once when the block is created).
__block base::OnceCallback<void(CredentialFetchResult)>
accumulatorInstance = accumulator;
[store
getCredentialsWithCompletion:^(NSArray<id<Credential>>* credentials) {
std::move(accumulatorInstance).Run({credentials});
}];
}
}
} // namespace credential_store_util