aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl/object_cast.ccm
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-06-22 16:56:39 +0100
committerLexi Winter <lexi@le-fay.org>2025-06-22 16:56:39 +0100
commitd6c3858418c4c00adb18d927135f73ed5a54564a (patch)
tree6a3bc3e70b3a63eadbf99955070adf1fa2e303e7 /nihil.ucl/object_cast.ccm
parent429be0c13e16b51b8fc7695c5f3ff65ac057fca7 (diff)
downloadnihil-d6c3858418c4c00adb18d927135f73ed5a54564a.tar.gz
nihil-d6c3858418c4c00adb18d927135f73ed5a54564a.tar.bz2
nihil.ucl: improve type safety
Diffstat (limited to 'nihil.ucl/object_cast.ccm')
-rw-r--r--nihil.ucl/object_cast.ccm81
1 files changed, 81 insertions, 0 deletions
diff --git a/nihil.ucl/object_cast.ccm b/nihil.ucl/object_cast.ccm
new file mode 100644
index 0000000..7291960
--- /dev/null
+++ b/nihil.ucl/object_cast.ccm
@@ -0,0 +1,81 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <cstdlib>
+
+#include <ucl.h>
+
+export module nihil.ucl:object_cast;
+
+import :type;
+import :object;
+import :array;
+
+namespace nihil::ucl {
+
+/*
+ * Ensure a UCL object is convertible to another type. Throws type_mismatch
+ * if not.
+ */
+
+// Implementation for basic types.
+template<datatype To>
+struct convert_check
+{
+ auto check(::ucl_object_t const *from) -> void
+ {
+ auto from_type = static_cast<object_type>(::ucl_object_type(from));
+ auto to_type = To::ucl_type;
+
+ // Converting from anything to object is permitted.
+ if (to_type == object_type::object)
+ return;
+
+ // Converting between two equal types is permitted.
+ if (from_type == to_type)
+ return;
+
+ // Otherwise, this is an error.
+ throw type_mismatch(to_type, from_type);
+ }
+};
+
+// Implementation for array.
+template<typename T>
+struct convert_check<array<T>>
+{
+ auto check(::ucl_object_t const *from) -> void
+ {
+ using To = array<T>;
+ auto from_type = static_cast<object_type>(::ucl_object_type(from));
+ auto to_type = To::ucl_type;
+
+ // If the source type is not an array, this is an error.
+ if (from_type != object_type::array)
+ throw type_mismatch(to_type, from_type);
+
+ for (std::size_t i = 0, size = ::ucl_array_size(from);
+ i < size; ++i) {
+ auto const *arr_obj = ::ucl_array_find_index(from, i);
+ convert_check<typename To::value_type>{}.check(arr_obj);
+ }
+ }
+};
+
+/*
+ * Convert a UCL object to another type.
+ */
+export template<datatype To>
+auto object_cast(object const &from) -> To
+{
+ convert_check<To>{}.check(from.get_ucl_object());
+
+ auto const *uobj = from.get_ucl_object();
+ auto *refptr = ::ucl_object_ref(uobj);
+ return To(refptr);
+}
+
+} // namespace nihil::ucl