blob: e27667d5936c84aa3a8bab5975efc5d2a5a15c0e [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/tag.h>
#include <lib/async_patterns/cpp/internal/task_queue.h>
#include <lib/async_patterns/cpp/pending_call.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;
template <typename F>
class Function;
/// 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 ReturnType, typename... Args>
class Function<ReturnType(Args...)> {
public:
/// Schedules the call to be asynchronously run on the receiver's
/// dispatcher.
///
/// See |async_patterns::BindForSending| for detailed requirements on |args|.
///
/// This operator returns a pending call. You may either:
///
/// - Make a fire-and-forget call, by discarding the returned object, or
/// - Get a promise carrying the return value of the function by calling
/// `promise()` on the object, yielding a |fpromise::promise<ReturnType>|, or
/// - Call `Then()` on the object and pass a |Callback<void(ReturnType)>|
///
/// See |async_patterns::PendingCall| for details.
///
/// Example:
///
/// async_patterns::Function<int(std::string)> parse = ...;
///
/// // Ignore the returned integer.
/// parse(std::string("abc"));
///
/// // Get a promise that will resolve when the function is asynchronously
/// // executed on the receiver's async dispatcher.
/// fpromise::promise<int> promise = parse(std::string("abc")).promise();
///
auto operator()(Args... args) {
ZX_DEBUG_ASSERT(task_queue_handle_.has_value());
return PendingCall{
BindForSending([f = function_](auto&&... args) { return (*f)(std::move(args)...); },
std::forward<Args>(args)...),
internal::SubmitWithTaskQueueHandle{task_queue_handle_}, internal::Tag<ReturnType>{}};
}
/// Returns a functor that performs the same actions as this |Function|, but returns
/// void, instead of potentially a promise object. This is useful when converting the
/// |Function| into a |fit::function<void(ReturnType)|.
auto ignore_result() && {
return [function = std::move(*this)](Args... args) mutable {
function(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<ReturnType(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_