about summary refs log tree commit diff
path: root/extra/guile/scm/val.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'extra/guile/scm/val.hpp')
-rw-r--r--extra/guile/scm/val.hpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/extra/guile/scm/val.hpp b/extra/guile/scm/val.hpp
new file mode 100644
index 000000000000..63d7189262da
--- /dev/null
+++ b/extra/guile/scm/val.hpp
@@ -0,0 +1,88 @@
+//
+// immer: immutable data structures for C++
+// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
+//
+// This software is distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
+//
+
+#pragma once
+
+#include <scm/detail/convert.hpp>
+
+namespace scm {
+namespace detail {
+
+template <typename T>
+struct convert_wrapper_type
+{
+    static T to_cpp(SCM v) { return T{v}; }
+    static SCM to_scm(T v) { return v.get(); }
+};
+
+struct wrapper
+{
+    wrapper() = default;
+    wrapper(SCM hdl) : handle_{hdl} {}
+    SCM get() const { return handle_; }
+    operator SCM () const { return handle_; }
+
+    bool operator==(wrapper other) { return handle_ == other.handle_; }
+    bool operator!=(wrapper other) { return handle_ != other.handle_; }
+
+protected:
+    SCM handle_ = SCM_UNSPECIFIED;
+};
+
+} // namespace detail
+
+struct val : detail::wrapper
+{
+    using base_t = detail::wrapper;
+    using base_t::base_t;
+
+    template <typename T,
+              typename = std::enable_if_t<
+                  (!std::is_same<std::decay_t<T>, val>{} &&
+                   !std::is_same<std::decay_t<T>, SCM>{})>>
+    val(T&& x)
+        : base_t(detail::to_scm(std::forward<T>(x)))
+    {}
+
+    template <typename T,
+              typename = std::enable_if_t<
+                  std::is_same<T, decltype(detail::to_cpp<T>(SCM{}))>{}>>
+    operator T() const { return detail::to_cpp<T>(handle_); }
+
+    template <typename T,
+              typename = std::enable_if_t<
+                  std::is_same<T&, decltype(detail::to_cpp<T>(SCM{}))>{}>>
+    operator T& () const { return detail::to_cpp<T>(handle_); }
+
+    template <typename T,
+              typename = std::enable_if_t<
+                  std::is_same<const T&, decltype(detail::to_cpp<T>(SCM{}))>{}>>
+    operator const T& () const { return detail::to_cpp<T>(handle_); }
+
+    val operator() () const
+    { return val{scm_call_0(get())}; }
+    val operator() (val a0) const
+    { return val{scm_call_1(get(), a0)}; }
+    val operator() (val a0, val a1) const
+    { return val{scm_call_2(get(), a0, a1)}; }
+    val operator() (val a0, val a1, val a3) const
+    { return val{scm_call_3(get(), a0, a1, a3)}; }
+};
+
+} // namespace scm
+
+#define SCM_DECLARE_WRAPPER_TYPE(cpp_name__)                            \
+    namespace scm {                                                     \
+    namespace detail {                                                  \
+    template <>                                                         \
+    struct convert<cpp_name__>                                          \
+        : convert_wrapper_type<cpp_name__> {};                          \
+    }} /* namespace scm::detail */                                      \
+    /**/
+
+SCM_DECLARE_WRAPPER_TYPE(val);