// -*- C++ -*-
// C++23 overlay for <functional>
// Adds: std::move_only_function
//
// Wraps the system <functional> and injects missing C++23 features.

#ifndef _OMNI_CPP23_FUNCTIONAL_OVERLAY
#define _OMNI_CPP23_FUNCTIONAL_OVERLAY

#include_next <functional>

#include <memory>
#include <type_traits>
#include <utility>

#if __cplusplus >= 202100L

#ifndef __cpp_lib_move_only_function
#define __cpp_lib_move_only_function 202110L

namespace std {

// ═══════════════════════════════════════════════════════════════════════════════
// std::move_only_function  (P0288R9)
// Type-erased callable wrapper that supports move-only callables.
// ═══════════════════════════════════════════════════════════════════════════════

template <class>
class move_only_function; // not defined

template <class R, class... Args>
class move_only_function<R(Args...)> {
  struct concept_t {
    virtual R invoke(Args...) = 0;
    virtual ~concept_t() = default;
  };

  template <class F>
  struct model_t final : concept_t {
    F fn_;
    template <class G>
    explicit model_t(G&& g) : fn_(std::forward<G>(g)) {}
    R invoke(Args... args) override {
      return std::invoke(fn_, std::forward<Args>(args)...);
    }
  };

  std::unique_ptr<concept_t> impl_;

public:
  move_only_function() noexcept = default;
  move_only_function(std::nullptr_t) noexcept {}

  template <class F>
    requires (!std::same_as<std::decay_t<F>, move_only_function>)
          && std::invocable<std::decay_t<F>&, Args...>
  move_only_function(F&& f)
    : impl_(std::make_unique<model_t<std::decay_t<F>>>(std::forward<F>(f))) {}

  move_only_function(move_only_function&&) noexcept = default;
  move_only_function& operator=(move_only_function&&) noexcept = default;

  move_only_function(const move_only_function&) = delete;
  move_only_function& operator=(const move_only_function&) = delete;

  R operator()(Args... args) {
    return impl_->invoke(std::forward<Args>(args)...);
  }

  explicit operator bool() const noexcept { return impl_ != nullptr; }

  void swap(move_only_function& other) noexcept { impl_.swap(other.impl_); }
  friend void swap(move_only_function& a, move_only_function& b) noexcept { a.swap(b); }
};

// const-qualified overload
template <class R, class... Args>
class move_only_function<R(Args...) const> {
  struct concept_t {
    virtual R invoke(Args...) const = 0;
    virtual ~concept_t() = default;
  };

  template <class F>
  struct model_t final : concept_t {
    F fn_;
    template <class G>
    explicit model_t(G&& g) : fn_(std::forward<G>(g)) {}
    R invoke(Args... args) const override {
      return std::invoke(fn_, std::forward<Args>(args)...);
    }
  };

  std::unique_ptr<concept_t> impl_;

public:
  move_only_function() noexcept = default;
  move_only_function(std::nullptr_t) noexcept {}

  template <class F>
    requires (!std::same_as<std::decay_t<F>, move_only_function>)
          && std::invocable<const std::decay_t<F>&, Args...>
  move_only_function(F&& f)
    : impl_(std::make_unique<model_t<std::decay_t<F>>>(std::forward<F>(f))) {}

  move_only_function(move_only_function&&) noexcept = default;
  move_only_function& operator=(move_only_function&&) noexcept = default;

  move_only_function(const move_only_function&) = delete;
  move_only_function& operator=(const move_only_function&) = delete;

  R operator()(Args... args) const {
    return impl_->invoke(std::forward<Args>(args)...);
  }

  explicit operator bool() const noexcept { return impl_ != nullptr; }
};

} // namespace std

#endif // __cpp_lib_move_only_function
#endif // __cplusplus >= 202100L
#endif // _OMNI_CPP23_FUNCTIONAL_OVERLAY
