blob: 3fd629bf2e40d82135d59e0f8bf62f66baad3261 [file] [log] [blame] [edit]
// Copyright 2023 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_ASYNC_PATTERNS_CPP_FUNCTION_H_
#define LIB_ASYNC_PATTERNS_CPP_FUNCTION_H_
#include <lib/async_patterns/cpp/internal/task_queue.h>
#include <lib/async_patterns/cpp/sendable.h>
#include <lib/fit/function.h>
#include <zircon/assert.h>
namespace async_patterns {
template <typename Owner>
class Receiver;
// An asynchronous |Function| that will always execute on the async dispatcher
// associated with a |Receiver|. Invoking this function translates to posting a
// task to the destination dispatcher. It will not block the caller.
//
// The receiver may not necessarily receive the function call. The call will be
// a no-op if:
// - The |Receiver| object goes out of scope.
// - The async dispatcher of the |Receiver| shuts down.
//
// A function can be invoked many times, and distributed to many senders. It is
// akin to a multi-producer, single-consumer, uni-directional channel. Calls
// posted to the same |Receiver| will be processed in the order they are made,
// regardless which |Function|s and |Callback|s they are made from.
template <typename... Args>
class Function {
public:
// Schedules the call to be asynchronously run on the receiver's
// dispatcher.
//
// See |async_patterns::BindForSending| for detailed requirements on |args|.
void operator()(Args... args) {
ZX_DEBUG_ASSERT(task_queue_handle_.has_value());
task_queue_handle_.Add(
BindForSending([f = function_](auto&&... args) { (*f)(std::move(args)...); },
std::forward<Args>(args)...));
}
private:
// The worst case scenario is a pointer-to-member (2 words) and a weak pointer (2 words).
// We can improve this further using custom weak pointer types if necessary.
using FunctionType = fit::inline_function<void(Args...), sizeof(void*) * 4>;
template <typename Owner>
friend class ::async_patterns::Receiver;
explicit Function(internal::TaskQueueHandle handle, FunctionType callback)
: task_queue_handle_(std::move(handle)),
function_(std::make_shared<FunctionType>(std::move(callback))) {}
internal::TaskQueueHandle task_queue_handle_;
// |function_| is reference counted because both |Function| and the remote
// task queue need to access it. |Function| uses it to schedule more calls.
// The task queue uses it to invoke user supplied logic.
std::shared_ptr<FunctionType> function_;
};
} // namespace async_patterns
#endif // LIB_ASYNC_PATTERNS_CPP_FUNCTION_H_