blob: 72919601f7f919f1f3b3c9b0ce2971ae7e03a56e (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
|