blob: 2853a761bfe5acace8faffa8f7eecef52c278283 [file] [log] [blame]
// 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_TESTING_NEXT_CPP_SYNC_PROXY_H_
#define LIB_ASYNC_PATTERNS_TESTING_NEXT_CPP_SYNC_PROXY_H_
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/async_patterns/testing/next/cpp/internal/sync_proxy_base.h>
#include <lib/fit/traits.h>
#define ASYNC_PATTERNS_DEFINE_SYNC_METHOD(CLASS_NAME, NAME) \
_ASYNC_PATTERNS_DEFINE_SYNC_METHOD_IMPL(CLASS_NAME, NAME)
#define ASYNC_PATTERNS_ADD_SYNC_METHOD(NAME, CLASS_NAME, MEMBER) \
_ASYNC_PATTERNS_ADD_SYNC_METHOD_IMPL(NAME, CLASS_NAME, MEMBER)
namespace async_patterns {
// |SyncProxy| is an ergonomic wrapper over |TestDispatcherBound| that simplifies
// the |SyncCall| syntax into direct function calls:
//
// auto r = sync_proxy.Foo(arg);
//
// is equivalent to
//
// auto r = test_dispatcher_bound.SyncCall(&T::Foo, arg);
//
// To use it, suppose there's a |Background| class with two methods |Foo|, |Bar|.
// We will choose |BackgroundSyncProxy| as the name of the sync proxy class.
// First tell the library about those methods using this macro:
//
// ASYNC_PATTERNS_DEFINE_SYNC_METHOD(BackgroundSyncProxy, Foo);
// ASYNC_PATTERNS_DEFINE_SYNC_METHOD(BackgroundSyncProxy, Bar);
//
// Then define |BackgroundSyncProxy| as the following type alias:
//
// using BackgroundSyncProxy = async_patterns::SyncProxy<
// Background,
// ASYNC_PATTERNS_ADD_SYNC_METHOD(BackgroundSyncProxy, Background, Foo),
// ASYNC_PATTERNS_ADD_SYNC_METHOD(BackgroundSyncProxy, Background, Bar)
// >;
//
// After that, you may use |BackgroundSyncProxy| like so:
//
// // The sync proxy supports the same construction API as |TestDispatcherBound|.
// BackgroundSyncProxy background(dispatcher);
// background.emplace(constructor_args);
//
// // But instead of |SyncCall|, you can directly call |Foo| and |Bar|.
// auto return_value = background.Foo(...);
// auto return_value = background.Bar(...);
//
// |SyncProxy| methods cannot be overloaded, or templated. If one of your member functions
// uses those features, you may call it through dispatcher bound:
//
// background
// .dispatcher_bound()
// .SyncCall<void(int, int)>(&Background::OverloadedFunction, 1, 2);
//
template <typename T, typename... Methods>
class SyncProxy : public internal::InheritFromArgs<T, Methods...> {
private:
using Methods_ = internal::InheritFromArgs<T, Methods...>;
public:
// Constructs a sync proxy with a |TestDispatcherBound| holding an object.
//
// See |async_patterns::TestDispatcherBound| for more information.
template <typename... Args>
explicit SyncProxy(async_dispatcher_t* dispatcher, std::in_place_t, Args&&... args)
: Methods_(&inner_), inner_(dispatcher, std::in_place, std::forward<Args>(args)...) {}
// Constructs a sync proxy with an empty |TestDispatcherBound|.
explicit SyncProxy(async_dispatcher_t* dispatcher) : Methods_(&inner_), inner_(dispatcher) {}
// Constructs an object inside the |TestDispatcherBound|.
//
// See |async_patterns::DispatcherBound<T>::emplace| for more information.
template <typename T2 = T, typename... Args>
void emplace(Args&&... args) {
inner_.template emplace<T2>(std::forward<Args>(args)...);
}
// If |has_value|, asynchronously destroys the managed |T| on a task
// posted to the dispatcher.
//
// See |async_patterns::DispatcherBound<T>::reset| for more information.
void reset() { inner_.reset(); }
// Returns if this object holds an instance of |T|.
//
// See |async_patterns::DispatcherBound<T>::reset| for more information.
bool has_value() const { return inner_.has_value(); }
// Returns a reference to the underlying |TestDispatcherBound|.
async_patterns::TestDispatcherBound<T>& dispatcher_bound() { return inner_.dispatcher_bound(); }
private:
SyncProxy(SyncProxy&&) noexcept = delete;
SyncProxy& operator=(SyncProxy&&) noexcept = delete;
SyncProxy(const SyncProxy&) noexcept = delete;
SyncProxy& operator=(const SyncProxy&) noexcept = delete;
async_patterns::TestDispatcherBound<T> inner_;
};
} // namespace async_patterns
#endif // LIB_ASYNC_PATTERNS_TESTING_NEXT_CPP_SYNC_PROXY_H_