#include <tuple>
#include <type_traits>
#include <unordered_map>
+#include <variant>
#include <boost/any.hpp>
#include <boost/format.hpp>
#include <boost/mpl/distance.hpp>
};
};
+// std::variant
+template<typename... TTypes>
+struct LuaContext::Pusher<std::variant<TTypes...>>
+{
+ static const int minSize = PusherMinSize<TTypes...>::size;
+ static const int maxSize = PusherMaxSize<TTypes...>::size;
+
+ static PushedObject push(lua_State* state, const std::variant<TTypes...>& value) noexcept {
+ PushedObject obj{state, 0};
+ std::visit([&](auto&& arg) {
+ using T = std::decay_t<decltype(arg)>;
+ obj = Pusher<T>::push(state, arg);
+ }, value);
+ return obj;
+ }
+};
+
// boost::optional
template<typename TType>
struct LuaContext::Pusher<boost::optional<TType>> {
};
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
-// variant
+// boost::variant
template<typename... TTypes>
struct LuaContext::Reader<boost::variant<TTypes...>>
{
}
};
+// std::variant
+template<typename... TTypes>
+struct LuaContext::Reader<std::variant<TTypes...>>
+{
+ using ReturnType = std::variant<TTypes...>;
+
+private:
+ template<std::size_t I = 0> static boost::optional<ReturnType> variantRead(lua_State* state, int index)
+ {
+ constexpr auto nbTypes = std::variant_size_v<ReturnType>;
+ if constexpr (I >= nbTypes) {
+ return boost::none;
+ }
+ if (const auto val = Reader<std::variant_alternative_t<I, ReturnType>>::read(state, index)) {
+ return ReturnType{*val};
+ }
+ if constexpr (I < (nbTypes - 1)) {
+ return variantRead<I + 1>(state, index);
+ }
+ return boost::none;
+ }
+
+public:
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ return variantRead(state, index);
+ }
+};
+
// reading a tuple
// tuple have an additional argument for their functions, that is the maximum size to read
// if maxSize is smaller than the tuple size, then the remaining parameters will be left to default value
}
}
+BOOST_AUTO_TEST_CASE(test_std_variant)
+{
+ LuaContext context;
+ context.writeFunction("testVariant", [](std::variant<int, std::string> incoming) -> std::variant<int, std::string> {
+ return incoming;
+ });
+
+ {
+ auto result = context.executeCode<std::variant<int, std::string>>("return testVariant(1)");
+ BOOST_REQUIRE(std::holds_alternative<int>(result));
+ BOOST_CHECK_EQUAL(std::get<int>(result), 1);
+ }
+
+ {
+ auto result = context.executeCode<std::variant<int, std::string>>("return testVariant('foo')");
+ BOOST_REQUIRE(std::holds_alternative<std::string>(result));
+ BOOST_CHECK_EQUAL(std::get<std::string>(result), "foo");
+ }
+
+ {
+ auto func = [&]() {
+ context.executeCode<std::variant<int, std::string>>("return testVariant(nil)");
+ };
+ BOOST_CHECK_THROW(func(), LuaContext::ExecutionErrorException);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()