/* * This source code is released into the public domain. */ module; #include #include 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 struct convert_check { auto check(::ucl_object_t const *from) -> void { auto from_type = static_cast(::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 struct convert_check> { auto check(::ucl_object_t const *from) -> void { using To = array; auto from_type = static_cast(::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{}.check(arr_obj); } } }; /* * Convert a UCL object to another type. */ export template auto object_cast(object const &from) -> To { auto uobj = from.get_ucl_object(); convert_check{}.check(uobj); return To(nihil::ucl::ref, uobj); } } // namespace nihil::ucl