include/wrenbind17/push.hpp

include/wrenbind17/push.hpp #

Namespaces #

Name
wrenbind17

Source code #

#pragma once

#include <wren.hpp>

#include <string>

#include "exception.hpp"
#include "object.hpp"

namespace wrenbind17 {
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    void getClassType(WrenVM* vm, std::string& module, std::string& name, size_t hash);
    bool isClassRegistered(WrenVM* vm, const size_t hash);
    detail::ForeignPtrConvertor* getClassCast(WrenVM* vm, size_t hash, size_t other);

    namespace detail {
        template <typename T> struct PushHelper;

        template <typename T> void pushAsConstRef(WrenVM* vm, int idx, const T& value) {
            static_assert(!std::is_same<int, typename std::remove_const<T>::type>(), "type can't be int");
            static_assert(!std::is_same<std::string, typename std::remove_const<T>::type>(),
                          "type can't be std::string");
            static_assert(!is_shared_ptr<T>::value, "type can't be shared_ptr<T>");
            try {
                std::string module;
                std::string klass;
                getClassType(vm, module, klass, typeid(T).hash_code());

                wrenEnsureSlots(vm, idx + 1);
                wrenGetVariable(vm, module.c_str(), klass.c_str(), idx);

                auto memory = wrenSetSlotNewForeign(vm, idx, idx, sizeof(ForeignObject<T>));
                auto* foreign = new (memory) ForeignObject<T>(std::make_shared<T>(value));
                (void)foreign;
            } catch (std::out_of_range& e) {
                (void)e;
                throw BadCast("Class type not registered in Wren VM");
            }
        }

        template <typename T> void pushAsMove(WrenVM* vm, int idx, T&& value) {
            static_assert(!std::is_same<int, T>(), "type can't be int");
            static_assert(!std::is_same<std::string, T>(), "type can't be std::string");
            static_assert(!is_shared_ptr<T>::value, "type can't be shared_ptr<T>");
            try {
                std::string module;
                std::string klass;
                getClassType(vm, module, klass, typeid(T).hash_code());

                wrenEnsureSlots(vm, idx + 1);
                wrenGetVariable(vm, module.c_str(), klass.c_str(), idx);

                auto memory = wrenSetSlotNewForeign(vm, idx, idx, sizeof(ForeignObject<T>));
                auto* foreign = new (memory) ForeignObject<T>(std::make_shared<T>(std::move(value)));
                (void)foreign;
            } catch (std::out_of_range& e) {
                (void)e;
                throw BadCast("Class type not registered in Wren VM");
            }
        }

        template <typename T> void pushAsPtr(WrenVM* vm, int idx, T* value) {
            static_assert(!std::is_same<int, T>(), "type can't be int");
            static_assert(!std::is_same<std::string, T>(), "type can't be std::string");
            static_assert(!is_shared_ptr<T>::value, "type can't be shared_ptr<T>");
            try {
                std::string module;
                std::string klass;
                getClassType(vm, module, klass, typeid(T).hash_code());

                wrenEnsureSlots(vm, idx + 1);
                wrenGetVariable(vm, module.c_str(), klass.c_str(), idx);

                auto memory = wrenSetSlotNewForeign(vm, idx, idx, sizeof(ForeignObject<T>));
                auto* foreign = new (memory) ForeignObject<T>(std::shared_ptr<T>(value, [](T* t) {}));
                (void)foreign;
            } catch (std::out_of_range& e) {
                (void)e;
                throw BadCast("Class type not registered in Wren VM");
            }
        }

        template <typename T> struct PushHelper {
            static inline void f(WrenVM* vm, int idx, const T& value) {
                pushAsConstRef(vm, idx, value);
            }

            static inline void f(WrenVM* vm, int idx, T&& value) {
                pushAsMove(vm, idx, std::move(value));
            }
        };

        template <typename T> struct PushHelper<const T> {
            static inline void f(WrenVM* vm, int idx, const T value) {
                PushHelper<T*>::f(vm, idx, value);
            }
        };

        template <typename T> struct PushHelper<T*> {
            static inline void f(WrenVM* vm, int idx, T* value) {
                pushAsPtr(vm, idx, value);
            }
        };

        template <typename T> struct PushHelper<const T*> {
            static inline void f(WrenVM* vm, int idx, const T* value) {
                PushHelper<T*>::f(vm, idx, const_cast<T*>(value));
            }
        };

        template <typename T> struct PushHelper<const T*&> {
            static inline void f(WrenVM* vm, int idx, const T*& value) {
                PushHelper<T*>::f(vm, idx, const_cast<T*>(value));
            }
        };

        template <typename T> struct PushHelper<T&> {
            static inline void f(WrenVM* vm, int idx, T& value) {
                PushHelper<T>::f(vm, idx, static_cast<const T&>(value));
            }
        };

        template <typename T> struct PushHelper<const T&> {
            static inline void f(WrenVM* vm, int idx, const T& value) {
                PushHelper<T>::f(vm, idx, static_cast<const T&>(value));
            }
        };

        // ============================================================================================================
        //                                       BASIC TYPES
        // ============================================================================================================

#define WRENBIND17_PUSH_HELPER(T, FUNC)                                                                                \
    template <> inline void PushHelper<T>::f(WrenVM* vm, int idx, const T& value) {                                    \
        FUNC;                                                                                                          \
    }                                                                                                                  \
    template <> inline void PushHelper<T>::f(WrenVM* vm, int idx, T&& value) {                                         \
        FUNC;                                                                                                          \
    }                                                                                                                  \
    template <> inline void PushHelper<const T>::f(WrenVM* vm, int idx, const T value) {                               \
        FUNC;                                                                                                          \
    }                                                                                                                  \
    template <> inline void PushHelper<T&>::f(WrenVM* vm, int idx, T& value) {                                         \
        FUNC;                                                                                                          \
    }                                                                                                                  \
    template <> inline void PushHelper<const T&>::f(WrenVM* vm, int idx, const T& value) {                             \
        FUNC;                                                                                                          \
    }                                                                                                                  \
    template <> inline void PushHelper<T*>::f(WrenVM* vm, int idx, T* value) {                                         \
        PushHelper<T>::f(vm, idx, *value);                                                                             \
    }                                                                                                                  \
    template <> inline void PushHelper<const T*>::f(WrenVM* vm, int idx, const T* value) {                             \
        PushHelper<T>::f(vm, idx, *value);                                                                             \
    }

        WRENBIND17_PUSH_HELPER(char, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(int8_t, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(short, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(int, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(long, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(long long, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(uint8_t, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(unsigned short, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(unsigned int, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(unsigned long, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(unsigned long long, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(float, wrenSetSlotDouble(vm, idx, static_cast<double>(value)));
        WRENBIND17_PUSH_HELPER(double, wrenSetSlotDouble(vm, idx, value));
        WRENBIND17_PUSH_HELPER(bool, wrenSetSlotBool(vm, idx, value));
        WRENBIND17_PUSH_HELPER(std::nullptr_t, wrenSetSlotNull(vm, idx));

        template <> struct PushHelper<std::string> {
            static inline void f(WrenVM* vm, int idx, const std::string value) {
                wrenSetSlotString(vm, idx, value.c_str());
            }
        };

        template <> struct PushHelper<std::string*> {
            static inline void f(WrenVM* vm, int idx, const std::string* value) {
                wrenSetSlotString(vm, idx, value->c_str());
            }
        };

        template <size_t N> struct PushHelper<const char (&)[N]> {
            static inline void f(WrenVM* vm, int idx, const char (&value)[N]) {
                wrenSetSlotString(vm, idx, value);
            }
        };

        template <size_t N> struct PushHelper<char (&)[N]> {
            static inline void f(WrenVM* vm, int idx, char (&value)[N]) {
                wrenSetSlotString(vm, idx, value);
            }
        };

        template <> struct PushHelper<const char*&> {
            static inline void f(WrenVM* vm, int idx, const char*& value) {
                wrenSetSlotString(vm, idx, value);
            }
        };

        template <> struct PushHelper<char*&> {
            static inline void f(WrenVM* vm, int idx, char*& value) {
                wrenSetSlotString(vm, idx, value);
            }
        };

        template <> struct PushHelper<const std::string> {
            static inline void f(WrenVM* vm, int idx, const std::string value) {
                wrenSetSlotString(vm, idx, value.c_str());
            }
        };

        template <> struct PushHelper<std::string&&> {
            static inline void f(WrenVM* vm, int idx, std::string&& value) {
                wrenSetSlotString(vm, idx, value.c_str());
            }
        };

        template <> struct PushHelper<std::string&> {
            static inline void f(WrenVM* vm, int idx, std::string& value) {
                wrenSetSlotString(vm, idx, value.c_str());
            }
        };

        template <> struct PushHelper<const std::string&> {
            static inline void f(WrenVM* vm, int idx, const std::string& value) {
                wrenSetSlotString(vm, idx, value.c_str());
            }
        };

        template <typename T> struct PushHelper<std::shared_ptr<T>> {
            static inline void f(WrenVM* vm, int idx, std::shared_ptr<T> value) {
                static_assert(!std::is_same<std::string, T>(), "type can't be std::string");
                static_assert(!is_shared_ptr<T>::value, "type can't be shared_ptr<T>");
                try {
                    std::string module;
                    std::string klass;
                    getClassType(vm, module, klass, typeid(T).hash_code());

                    wrenEnsureSlots(vm, idx + 1);
                    wrenGetVariable(vm, module.c_str(), klass.c_str(), idx);

                    auto memory = wrenSetSlotNewForeign(vm, idx, idx, sizeof(ForeignObject<T>));
                    auto* foreign = new (memory) ForeignObject<T>(value);
                    (void)foreign;
                } catch (std::out_of_range& e) {
                    (void)e;
                    throw BadCast("Class type not registered in Wren VM");
                }
            }
        };

        template <typename T> struct PushHelper<const std::shared_ptr<T>> {
            static inline void f(WrenVM* vm, int idx, const std::shared_ptr<T> value) {
                PushHelper<std::shared_ptr<T>>::f(vm, idx, value);
            }
        };

        template <typename T> struct PushHelper<std::shared_ptr<T>&&> {
            static inline void f(WrenVM* vm, int idx, std::shared_ptr<T>&& value) {
                PushHelper<std::shared_ptr<T>>::f(vm, idx, std::move(value));
            }
        };

        template <typename T> struct PushHelper<std::shared_ptr<T>&> {
            static inline void f(WrenVM* vm, int idx, std::shared_ptr<T>& value) {
                PushHelper<std::shared_ptr<T>>::f(vm, idx, value);
            }
        };

        template <typename T> struct PushHelper<const std::shared_ptr<T>&> {
            static inline void f(WrenVM* vm, int idx, const std::shared_ptr<T>& value) {
                PushHelper<std::shared_ptr<T>>::f(vm, idx, value);
            }
        };

        template <typename Iter> inline void loopAndPushIterable(WrenVM* vm, const int idx, Iter begin, Iter end) {
            using T = typename std::iterator_traits<Iter>::value_type;
            wrenSetSlotNewList(vm, idx);
            auto i = 0;
            for (auto it = begin; it != end; ++it) {
                PushHelper<T>::f(vm, idx + 1, *it);
                wrenInsertInList(vm, idx, i++, idx + 1);
            }
        }

        template <typename Iter> inline void loopAndPushKeyPair(WrenVM* vm, const int idx, Iter begin, Iter end) {
            using T = typename std::iterator_traits<Iter>::value_type;
            using Key = typename T::first_type;
            using Value = typename T::second_type;
            wrenSetSlotNewMap(vm, idx);
            wrenEnsureSlots(vm, 3);
            for (auto it = begin; it != end; ++it) {
                PushHelper<Key>::f(vm, idx + 1, std::forward<Key>(it->first));
                PushHelper<Value>::f(vm, idx + 2, std::forward<Value>(it->second));
                wrenSetMapValue(vm, idx, idx + 1, idx + 2);
            }
        }
    } // namespace detail
#endif
} // namespace wrenbind17

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