#ifndef UI_GFX_X_FUTURE_H_
#define UI_GFX_X_FUTURE_H_
#include "base/component_export.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
class Connection;
class Event;
class COMPONENT_EXPORT(X11) FutureImpl {
public:
FutureImpl(Connection* connection,
SequenceType sequence,
bool generates_reply,
const char* request_name_for_tracing);
void Wait();
void DispatchNow();
bool AfterEvent(const Event& event) const;
void Sync(RawReply* raw_reply, std::unique_ptr<Error>* error);
void OnResponse(ResponseCallback callback);
void UpdateRequestHandler(ResponseCallback callback);
void ProcessResponse();
void TakeResponse(RawReply* reply, std::unique_ptr<Error>* error);
SequenceType sequence() const { return sequence_; }
bool generates_reply() const { return generates_reply_; }
const char* request_name_for_tracing() const {
return request_name_for_tracing_;
}
private:
raw_ptr<Connection, DanglingUntriaged> connection_ = nullptr;
SequenceType sequence_ = 0;
bool generates_reply_ = false;
const char* request_name_for_tracing_ = nullptr;
};
class COMPONENT_EXPORT(X11) FutureBase {
public:
FutureBase();
explicit FutureBase(std::unique_ptr<FutureImpl> impl);
FutureBase(FutureBase&&);
FutureBase& operator=(FutureBase&&);
~FutureBase();
void Wait();
void DispatchNow();
bool AfterEvent(const Event& event) const;
protected:
FutureImpl* impl() { return impl_.get(); }
private:
std::unique_ptr<FutureImpl> impl_;
};
template <typename Reply>
class Future : public FutureBase {
public:
using Callback = base::OnceCallback<void(Response<Reply> response)>;
Future() = default;
explicit Future(std::unique_ptr<FutureImpl> impl)
: FutureBase(std::move(impl)) {
static_assert(sizeof(Future<Reply>) == sizeof(FutureBase),
"Future must not have any members so that it can be sliced "
"to FutureBase");
}
Response<Reply> Sync() {
if (!impl()) {
return {nullptr, nullptr};
}
RawReply raw_reply;
std::unique_ptr<Error> error;
impl()->Sync(&raw_reply, &error);
std::unique_ptr<Reply> reply;
if (raw_reply) {
auto buf = ReadBuffer(raw_reply);
reply = detail::ReadReply<Reply>(&buf);
}
return {std::move(reply), std::move(error)};
}
void OnResponse(Callback callback) {
if (!impl()) {
std::move(callback).Run({nullptr, nullptr});
return;
}
auto wrapper = [](Callback callback, RawReply raw_reply,
std::unique_ptr<Error> error) {
std::unique_ptr<Reply> reply;
if (raw_reply) {
ReadBuffer buf(raw_reply);
reply = detail::ReadReply<Reply>(&buf);
}
std::move(callback).Run({std::move(reply), std::move(error)});
};
impl()->OnResponse(base::BindOnce(wrapper, std::move(callback)));
}
void IgnoreError() {
OnResponse(base::BindOnce([](Response<Reply>) {}));
}
};
template <>
inline Response<void> Future<void>::Sync() {
if (!impl()) {
return Response<void>{nullptr};
}
RawReply raw_reply;
std::unique_ptr<Error> error;
impl()->Sync(&raw_reply, &error);
CHECK(!raw_reply);
return Response<void>(std::move(error));
}
template <>
inline void Future<void>::OnResponse(Callback callback) {
if (!impl()) {
std::move(callback).Run(Response<void>(nullptr));
return;
}
auto wrapper = [](Callback callback, RawReply reply,
std::unique_ptr<Error> error) {
CHECK(!reply);
std::move(callback).Run(Response<void>{std::move(error)});
};
impl()->OnResponse(base::BindOnce(wrapper, std::move(callback)));
}
}
#endif