include/wrenbind17/method.hpp

include/wrenbind17/method.hpp #

Namespaces #

Name
wrenbind17

Classes #

Name
class wrenbind17::Method

Source code #

#pragma once

#include <wren.hpp>

#include <memory>

#include "any.hpp"
#include "exception.hpp"

namespace wrenbind17 {
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    namespace detail {
        inline void pushArgs(WrenVM* vm, int idx) {
            (void)vm;
            (void)idx;
        }

        template <typename First, typename... Other>
        inline void pushArgs(WrenVM* vm, int idx, First&& first, Other&&... other) {
            PushHelper<First>::f(vm, idx, std::forward<First>(first));
            pushArgs(vm, ++idx, std::forward<Other>(other)...);
        }

        template <typename... Args> struct CallAndReturn {
            static Any func(WrenVM* vm, WrenHandle* handle, WrenHandle* func, Args&&... args) {
                constexpr auto n = sizeof...(Args);
                wrenEnsureSlots(vm, n + 1);
                wrenSetSlotHandle(vm, 0, handle);

                pushArgs(vm, 1, std::forward<Args>(args)...);

                if (wrenCall(vm, func) != WREN_RESULT_SUCCESS) {
                    throw RuntimeError(getLastError(vm));
                }

                return getSlot<Any>(vm, 0);
            }
        };
    } // namespace detail
#endif

    class Method {
    public:
        Method() = default;

        Method(std::shared_ptr<Handle> variable, std::shared_ptr<Handle> handle)
            : variable(std::move(variable)), handle(std::move(handle)) {
        }

        ~Method() {
            reset();
        }

        template <typename... Args> Any operator()(Args&&... args) {
            if (const auto ptr = handle->getVmWeak().lock().get()) {
                return detail::CallAndReturn<Args...>::func(ptr, variable->getHandle(), handle->getHandle(),
                                                            std::forward<Args>(args)...);
            } else {
                throw RuntimeError("Invalid handle");
            }
        }

        operator bool() const {
            return variable && handle;
        }

        void reset() {
            handle.reset();
            variable.reset();
        }

    private:
        std::shared_ptr<Handle> variable;
        std::shared_ptr<Handle> handle;
    };
} // namespace wrenbind17

Updated on 17 October 2023 at 12:26:25 UTC