blob: c3b6affa0f28de49eb3e66462aada3f61a974f3d [file] [log] [blame]
// Copyright 2022 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_SYS_FUZZING_COMMON_ASYNC_TYPES_H_
#define SRC_SYS_FUZZING_COMMON_ASYNC_TYPES_H_
// This file contains aliases and helper functions for commonly used types from fpromise in order to
// reduce the "clutter" of having fully-qualified types everywhere.
//
// For example, a promise that creates some value before making a FIDL call might go from looking
// like this:
//
// return fpromise::make_promise([](fpromise::context& context) ->
// fpromise::result<V, zx_status_t> {
// return fpromise::ok(CreateValue());
// })
// .and_then([](V& value){
// fpromise::bridge<V, zx_status_t> bridge;
// MakeFidlCall(value, [completer = std::move(bridge.completer)]
// (fpromise::result<U, zx_status_t>& result) {
// if (result.is_error()) {
// completer.complete_error(result.error());
// return;
// }
// completer.complete_ok(result.take_value());
// });
// return consumer.promise_or(fpromise::error(ZX_ERR_CANCELED));
// });
//
// to this:
//
// return fpromise::make_promise([](Context& context) -> ZxResult<V> {
// return fpromise::ok(CreateValue());
// })
// .and_then([](V& value){
// ZxBridge<V> bridge;
// MakeFidlCall(value, ZxBind(std::move(bridge.completer)));
// return consumer.promise_or(fpromise::error(ZX_ERR_CANCELED));
// });
//
#include <lib/async/cpp/executor.h>
#include <lib/fpromise/barrier.h>
#include <lib/fpromise/bridge.h>
#include <lib/fpromise/promise.h>
#include <lib/fpromise/result.h>
#include <lib/fpromise/scope.h>
#include <lib/fpromise/sequencer.h>
#include <zircon/types.h>
namespace fuzzing {
// All tasks should be scheduled on a common executor.
using ExecutorPtr = std::shared_ptr<async::Executor>;
ExecutorPtr MakeExecutor(async_dispatcher_t* dispatcher);
// Types templated on values and errors, for both generic errors and zx_status_t.
//
// This will generate both an |Aliased| and |ZxAliased| type for the given |fpromise::original|,
// e.g. WRAP_RESULT_TYPE(fpromise::result, Result) produces:
//
// * |Result<V, E>| which aliases |fpromise::result<V, E>|, and
// * |ZxResult<V, E>| which aliases |fpromise::result<V, zx_status_t>|.
//
#define WRAP_RESULT_TYPE(original, Aliased) \
template <typename V = void, typename E = void> \
using Aliased = original<V, E>; \
template <typename V = void> \
using Zx##Aliased = original<V, zx_status_t>
WRAP_RESULT_TYPE(fpromise::result, Result);
WRAP_RESULT_TYPE(fpromise::promise, Promise);
WRAP_RESULT_TYPE(fpromise::future, Future);
WRAP_RESULT_TYPE(fpromise::bridge, Bridge);
WRAP_RESULT_TYPE(fpromise::completer, Completer);
WRAP_RESULT_TYPE(fpromise::consumer, Consumer);
#undef WRAP_RESULT_TYPE
// Like |Completer::bind|, but can handle |zx_status_t| errors. This is useful for bridging FIDL
// callbacks for methods like "... -> ... error zx.Status;".
template <typename V = void>
inline fit::function<void(ZxResult<V>)> ZxBind(typename ZxBridge<V>::completer_type&& completer) {
return [completer = std::move(completer)](ZxResult<V> result) mutable {
if (result.is_error()) {
completer.complete_error(result.error());
return;
}
if constexpr (std::is_same<V, void>::value) {
completer.complete_ok();
} else {
completer.complete_ok(result.take_value());
}
};
}
// Converts a status code result to a |ZxResult|.
ZxResult<> AsZxResult(zx_status_t status);
ZxResult<> AsZxResult(const Result<zx_status_t>& result);
// Returns a promise to wait for a `Consumer` to be completed by its associated `Completer`.
//
// These explicit overrides do not return values on success. They return ZX_ERR_CANCELED if the
// associated completer is destroyed.
//
ZxPromise<> AwaitConsumer(Consumer<> consumer);
ZxPromise<> AwaitConsumer(Consumer<zx_status_t> consumer);
ZxPromise<> AwaitConsumer(ZxConsumer<> consumer);
// Like `AwaitConsumer` above, but these also returns a value on success.
template <typename T>
ZxPromise<T> AwaitConsumer(Consumer<T> consumer) {
return consumer.promise_or(fpromise::error()).or_else([]() {
return fpromise::error(ZX_ERR_CANCELED);
});
}
template <typename T>
ZxPromise<T> AwaitConsumer(ZxConsumer<T> consumer) {
return consumer.promise_or(fpromise::error(ZX_ERR_CANCELED));
}
// Returns a promise to wait for a bridge's consumer to be completed by its associated `Completer`.
//
// These explicit overrides do not return values on success. They return ZX_ERR_CANCELED if the
// associated completer is destroyed.
//
ZxPromise<> ConsumeBridge(Bridge<>& bridge);
ZxPromise<> ConsumeBridge(Bridge<zx_status_t>& bridge);
// Like `ConsumeBridge` above, but also returns a value on success.
template <typename B>
ZxPromise<typename B::value_type> ConsumeBridge(B& bridge) {
return AwaitConsumer(std::move(bridge.consumer));
}
// Additional supporting types from fpromise.
using Barrier = fpromise::barrier;
using Context = fpromise::context;
using Scope = fpromise::scope;
using Sequencer = fpromise::sequencer;
} // namespace fuzzing
#endif // SRC_SYS_FUZZING_COMMON_ASYNC_TYPES_H_