]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
LuaWrapper: Add support for `std::optional`
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 22 Jul 2025 12:05:56 +0000 (14:05 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 22 Jul 2025 14:44:01 +0000 (16:44 +0200)
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
ext/luawrapper/include/LuaContext.hpp
pdns/test-luawrapper.cc

index 655375e7c9d6a8298cd8eee07bd66e8e1f5f80b1..66f879eb8369405bf3cb7401186e6eb5cdc67be4 100644 (file)
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <list>
 #include <map>
 #include <memory>
+#include <optional>
 #include <random>
 #include <set>
 #include <stdexcept>
@@ -1873,8 +1874,8 @@ private:
     // the only case where "min != max" is with boost::optional at the end of the list
     template<typename... TArgumentsList>
     struct FunctionArgumentsCounter {};
-    
-    // true is the template parameter is a boost::optional
+
+    // true if the template parameter is a boost::optional or std::optional
     template<typename T>
     struct IsOptional : public std::false_type {};
 };
@@ -1970,6 +1971,8 @@ struct LuaContext::FunctionArgumentsCounter<> {
 // implementation of IsOptional
 template<typename T>
 struct LuaContext::IsOptional<boost::optional<T>> : public std::true_type {};
+template<typename T>
+struct LuaContext::IsOptional<std::optional<T>> : public std::true_type {};
 
 // implementation of LuaFunctionCaller
 template<typename TFunctionType>
@@ -2542,6 +2545,25 @@ struct LuaContext::Pusher<boost::optional<TType>> {
     }
 };
 
+// std::optional
+template<typename TType>
+struct LuaContext::Pusher<std::optional<TType>> {
+    typedef Pusher<typename std::decay<TType>::type>
+        UnderlyingPusher;
+
+    static const int minSize = UnderlyingPusher::minSize < 1 ? UnderlyingPusher::minSize : 1;
+    static const int maxSize = UnderlyingPusher::maxSize > 1 ? UnderlyingPusher::maxSize : 1;
+
+    static PushedObject push(lua_State* state, const std::optional<TType>& value) noexcept {
+        if (value.has_value()) {
+            return UnderlyingPusher::push(state, value.value());
+        } else {
+            lua_pushnil(state);
+            return PushedObject{state, 1};
+        }
+    }
+};
+
 // tuple
 template<typename... TTypes>
 struct LuaContext::Pusher<std::tuple<TTypes...>> {
@@ -2891,6 +2913,22 @@ struct LuaContext::Reader<boost::optional<TType>>
     }
 };
 
+template<typename TType>
+struct LuaContext::Reader<std::optional<TType>>
+{
+    static auto read(lua_State* state, int index)
+        -> boost::optional<std::optional<TType>>
+    {
+        if (lua_isnil(state, index)) {
+          return boost::optional<std::optional<TType>>{std::optional<TType>()};
+        }
+        if (auto&& other = Reader<TType>::read(state, index)) {
+            return std::move(std::optional<TType>(*other));
+        }
+        return boost::none;
+    }
+};
+
 // variant
 template<typename... TTypes>
 struct LuaContext::Reader<boost::variant<TTypes...>>
index dd01254db9096e2ddd3825ddaff1cf6f70108cda..c4d2e34921b1f8ec50acbb1bf9c1d9b2132cdc56 100644 (file)
@@ -35,3 +35,39 @@ BOOST_AUTO_TEST_CASE(test_registerFunction)
 }
 
 BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(test_luawrapper)
+
+BOOST_AUTO_TEST_CASE(test_boost_optional)
+{
+  LuaContext context;
+  context.writeFunction("testOptional", [](boost::optional<int> in) -> boost::optional<int> {
+    return in;
+  });
+
+  BOOST_REQUIRE(!context.executeCode<boost::optional<int>>("return testOptional(nil)"));
+
+  {
+    auto result = context.executeCode<boost::optional<int>>("return testOptional(1)");
+    BOOST_REQUIRE(result);
+    BOOST_CHECK_EQUAL(*result, 1);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_std_optional)
+{
+  LuaContext context;
+  context.writeFunction("testOptional", [](std::optional<int> in) -> std::optional<int> {
+    return in;
+  });
+
+  BOOST_REQUIRE(!context.executeCode<std::optional<int>>("return testOptional(nil)"));
+
+  {
+    auto result = context.executeCode<std::optional<int>>("return testOptional(1)");
+    BOOST_REQUIRE(result);
+    BOOST_CHECK_EQUAL(*result, 1);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()