910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GPU_WEBGPU_CALLBACK_H_
#define GPU_WEBGPU_CALLBACK_H_

#include <memory>

#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/types/is_instantiation.h"

namespace gpu::webgpu {

// WGPUCallback<Callback> is a heap-allocated version of
// base::OnceCallback or base::RepeatingCallback.
// It is allocated on the heap so that it can be reinterpret_cast to/from
// void* and passed to WGPU C callbacks.
//
// Example:
//   WGPUOnceCallback<F>* callback =
//     BindWGPUOnceCallback(func, arg1);
//
//   // |someWGPUFunction| expects callback function with arguments:
//   //    Args... args, void* userdata.
//   // When it is called, it will forward to func(arg1, args...).
//   GetProcs().someWGPUFunction(
//     callback->UnboundCallback(), callback->AsUserdata());
template <typename Callback>
class WGPUCallbackBase;

template <typename Callback>
class WGPUOnceCallback;

template <typename Callback>
class WGPURepeatingCallback;

template <template <typename> class BaseCallbackTemplate,
          typename R,
          typename... Args>
  requires base::IsBaseCallback<BaseCallbackTemplate<R(Args...)>>
class WGPUCallbackBase<BaseCallbackTemplate<R(Args...)>> {
  using BaseCallback = BaseCallbackTemplate<R(Args...)>;

 public:
  explicit WGPUCallbackBase(BaseCallback callback)
      : callback_(std::move(callback)) {}

  void* AsUserdata() { return static_cast<void*>(this); }

 protected:
  using UnboundCallbackFunction = R (*)(Args..., void*);

  static WGPUCallbackBase* FromUserdata(void* userdata) {
    return static_cast<WGPUCallbackBase*>(userdata);
  }

  R Run(Args... args) &&
    requires base::is_instantiation<BaseCallback, base::OnceCallback>
  {
    return std::move(callback_).Run(std::forward<Args>(args)...);
  }

  R Run(Args... args) const&
    requires base::is_instantiation<BaseCallback, base::RepeatingCallback>
  {
    return callback_.Run(std::forward<Args>(args)...);
  }

 private:
  BaseCallback callback_;
};

template <typename R, typename... Args>
class WGPUOnceCallback<R(Args...)>
    : public WGPUCallbackBase<base::OnceCallback<R(Args...)>> {
  using BaseCallback = base::OnceCallback<R(Args...)>;

 public:
  using WGPUCallbackBase<BaseCallback>::WGPUCallbackBase;

  typename WGPUCallbackBase<BaseCallback>::UnboundCallbackFunction
  UnboundCallback() {
    return CallUnboundOnceCallback;
  }

 private:
  static R CallUnboundOnceCallback(Args... args, void* handle) {
    // After this non-repeating callback is run, it should delete itself.
    auto callback =
        std::unique_ptr<WGPUOnceCallback>(static_cast<WGPUOnceCallback*>(
            WGPUCallbackBase<BaseCallback>::FromUserdata(handle)));
    return std::move(*callback).Run(std::forward<Args>(args)...);
  }
};

template <typename R, typename... Args>
class WGPURepeatingCallback<R(Args...)>
    : public WGPUCallbackBase<base::RepeatingCallback<R(Args...)>> {
  using BaseCallback = base::RepeatingCallback<R(Args...)>;

 public:
  using WGPUCallbackBase<BaseCallback>::WGPUCallbackBase;

  typename WGPUCallbackBase<BaseCallback>::UnboundCallbackFunction
  UnboundCallback() {
    return CallUnboundRepeatingCallback;
  }

 private:
  static R CallUnboundRepeatingCallback(Args... args, void* handle) {
    return static_cast<WGPURepeatingCallback*>(
               WGPUCallbackBase<BaseCallback>::FromUserdata(handle))
        ->Run(std::forward<Args>(args)...);
  }
};

template <typename CallbackType>
  requires base::is_instantiation<CallbackType, base::OnceCallback>
auto MakeWGPUOnceCallback(CallbackType&& cb) {
  return new gpu::webgpu::WGPUOnceCallback<typename CallbackType::RunType>(
      std::move(cb));
}

template <typename FunctionType, typename... BoundParameters>
  requires(!base::internal::kIsWeakMethod<
           base::internal::FunctorTraits<FunctionType,
                                         BoundParameters...>::is_method,
           BoundParameters...>)
auto BindWGPUOnceCallback(FunctionType&& function,
                          BoundParameters&&... bound_parameters) {
  return MakeWGPUOnceCallback(
      base::BindOnce(std::forward<FunctionType>(function),
                     std::forward<BoundParameters>(bound_parameters)...));
}

template <typename CallbackType>
  requires base::is_instantiation<CallbackType, base::RepeatingCallback>
auto MakeWGPURepeatingCallback(CallbackType&& cb) {
  return new gpu::webgpu::WGPURepeatingCallback<typename CallbackType::RunType>(
      std::move(cb));
}

template <typename FunctionType, typename... BoundParameters>
auto BindWGPURepeatingCallback(FunctionType&& function,
                               BoundParameters&&... bound_parameters) {
  return MakeWGPURepeatingCallback(
      base::BindRepeating(std::forward<FunctionType>(function),
                          std::forward<BoundParameters>(bound_parameters)...));
}

}  // namespace gpu::webgpu

#endif  // GPU_WEBGPU_CALLBACK_H_