#ifndef PYTHON_PYBIND11_UTILS_SMART_VARIANT_WRAPPER_H #define PYTHON_PYBIND11_UTILS_SMART_VARIANT_WRAPPER_H #include #include #include #include #include "smart_variant.h" namespace mo2::python { namespace detail { // simple helper class that expose a ::type attribute which is U is I is in Is, // V otherwise template struct wrap_arg; template struct wrap_arg> { using type = std::conditional_t...>, U, V>; }; // helper type for wrap_arg template using wrap_arg_t = typename wrap_arg::type; template auto wrap_arguments_impl(std::index_sequence, Fn&& fn, R (*)(Args...), std::index_sequence) { return [fn = std::forward(fn)]( wrap_arg_t>... args) { return std::invoke(fn, std::forward(args)...); }; } template auto make_convertible_index_sequence(std::index_sequence) { return std::index_sequence<(std::is_convertible_v ? Is : -1)...>{}; } template auto wrap_arguments_impl(Fn&& fn, R (*sg)(Args...)) { if constexpr (sizeof...(Is) == 0) { return wrap_arguments_impl( make_convertible_index_sequence( std::make_index_sequence{}), std::forward(fn), sg, std::make_index_sequence{}); } else { return wrap_arguments_impl( std::index_sequence{}, std::forward(fn), sg, std::make_index_sequence{}); } } template auto wrap_return_impl(Fn&& fn, R (*)(Args...)) { return [fn = std::forward(fn)](Args... args) { return T{std::invoke(fn, std::forward(args)...)}; }; } // make_python_function_signature: return a null-pointer with the proper type // for the given function template struct function_signature { using type = pybind11::detail::function_signature_t>; }; template struct function_signature { using type = R(Args...); }; template struct function_signature { using type = R(C*, Args...); }; template struct function_signature { using type = R(C*, Args...); }; template struct function_signature { using type = R(const C*, Args...); }; template struct function_signature { using type = R(const C*, Args...); }; template using function_signature_t = typename function_signature::type; template class wrap_type_caster { using variant_type = std::variant; using variant_caster = pybind11::detail::make_caster; public: PYBIND11_TYPE_CASTER(Type, variant_caster::name); bool load(pybind11::handle src, bool convert) { variant_caster caster; if (!caster.load(src, convert)) { return false; } value = std::visit( [](auto const& fn) { return Type(fn); }, static_cast(caster)); return true; } static pybind11::handle cast(const Type& src, pybind11::return_value_policy policy, pybind11::handle parent) { return variant_caster::cast(variant_type(std::in_place_index<0>, src), policy, parent); } }; } // namespace detail // wrap the given function-like object to accept T instead of the specified // arguments at the specified positions // // if the list of positions is empty, replace all arguments that can be converted to // T // template auto wrap_arguments(Fn&& fn) { return detail::wrap_arguments_impl( std::forward(fn), (mo2::python::detail::function_signature_t*)nullptr); } // wrap the given function-like object to return T instead of the specified type // template auto wrap_return(Fn&& fn) { return detail::wrap_return_impl( std::forward(fn), (mo2::python::detail::function_signature_t*)nullptr); } } // namespace mo2::python namespace pybind11::detail { template struct type_caster<::mo2::python::smart_variant> : variant_caster<::mo2::python::smart_variant> {}; } // namespace pybind11::detail #endif