blob: 4028dfe68d50a77873362521e62ac10da0a0aca1 [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 LIB_CALLBACK_OPERATION_SERIALIZER_H_
#define LIB_CALLBACK_OPERATION_SERIALIZER_H_
#include <functional>
#include <queue>
#include <lib/fit/function.h>
#include "lib/fxl/functional/make_copyable.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace callback {
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() {}
// 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 empty() { return queued_operations_.empty(); }
void set_on_empty(fit::closure on_empty) { on_empty_ = std::move(on_empty); }
private:
void UpdateOperationsAndCallNext() {
queued_operations_.pop();
if (!queued_operations_.empty()) {
queued_operations_.front()();
} else if (on_empty_) {
on_empty_();
}
}
std::queue<fit::closure> queued_operations_;
fit::closure on_empty_;
// This must be the last member of the class.
fxl::WeakPtrFactory<OperationSerializer> weak_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(OperationSerializer);
};
} // namespace callback
#endif // LIB_CALLBACK_OPERATION_SERIALIZER_H_