diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-06-22 16:56:39 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-06-22 16:56:39 +0100 |
| commit | d6c3858418c4c00adb18d927135f73ed5a54564a (patch) | |
| tree | 6a3bc3e70b3a63eadbf99955070adf1fa2e303e7 /nihil.ucl/object_cast.ccm | |
| parent | 429be0c13e16b51b8fc7695c5f3ff65ac057fca7 (diff) | |
| download | nihil-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.ccm | 81 |
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 |
