blob: 00ddf51b8039c01d207b912120aa4b96b182ab39 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LEDGER_LIB_CALLBACK_OPERATION_SERIALIZER_H_
#define SRC_LEDGER_LIB_CALLBACK_OPERATION_SERIALIZER_H_
#include <lib/fit/function.h>
#include <functional>
#include <queue>
#include "src/ledger/lib/memory/weak_ptr.h"
namespace ledger {
namespace internal {
// Defines the type of the callback function to be used in Serialize method of
// OperationSerializer. Note that this is necessary for template resolution:
// Trying to directly define callback as `fit::function<void(C...)>` causes a
// compile error when calling Serialize, as automatic cast of lambdas fails.
template <class... C>
struct Signature {
using CallbackType = void(C...);
};
} // namespace internal
// OperationSerializer can be used to serialize a set of operations. A typical
// usage example would be:
// OperationSerializer serializer;
//
// and then for each operation to be serialized:
// fit::function<void(Status)> on_done = ...;
// serializer.Serialize<Status>(std::move(on_done),
// [](fit::function<void(Status)> callback) {
// // Code for the operation...
// callback(Status::/* result */);
// });
class OperationSerializer {
public:
OperationSerializer() : weak_factory_(this) {}
OperationSerializer(const OperationSerializer&) = delete;
OperationSerializer& operator=(const OperationSerializer&) = delete;
~OperationSerializer() {}
// Queues operations so that they are serialized: an operation is executed
// only when all previous operations registered through this method have
// terminated by calling their callbacks. When |operation| terminates,
// |callback| is called with the result returned by |operation|.
//
// The resolved type of this method is
// void Serialize(fit::function<void(C...)> callback,
// fit::function<void(fit::function<void(C...)>)> operation)
template <class... C>
void Serialize(
fit::function<typename internal::Signature<C...>::CallbackType> callback,
fit::function<void(fit::function<typename internal::Signature<C...>::CallbackType>)>
operation) {
auto closure = [this, callback = std::move(callback),
operation = std::move(operation)]() mutable {
operation(
[weak_ptr_ = weak_factory_.GetWeakPtr(), callback = std::move(callback)](C... args) {
// First run the callback and then, make sure this has not been deleted.
callback(std::forward<C>(args)...);
if (!weak_ptr_) {
return;
}
weak_ptr_->UpdateOperationsAndCallNext();
});
};
queued_operations_.emplace(std::move(closure));
if (queued_operations_.size() == 1) {
queued_operations_.front()();
}
}
// Returns true if there are no more operations in the queue or false
// otherwise.
bool IsDiscardable() const { return queued_operations_.empty(); }
void SetOnDiscardable(fit::closure on_discardable) {
on_discardable_ = std::move(on_discardable);
}
private:
void UpdateOperationsAndCallNext() {
queued_operations_.pop();
if (!queued_operations_.empty()) {
queued_operations_.front()();
} else if (on_discardable_) {
on_discardable_();
}
}
std::queue<fit::closure> queued_operations_;
fit::closure on_discardable_;
// This must be the last member of the class.
WeakPtrFactory<OperationSerializer> weak_factory_;
};
} // namespace ledger
#endif // SRC_LEDGER_LIB_CALLBACK_OPERATION_SERIALIZER_H_