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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
// This source code is released into the public domain.
module;
#include <ucl.h>
export module nihil.ucl:boolean;
import nihil.std;
import nihil.core;
import :object;
namespace nihil::ucl {
export struct boolean final : object
{
using contained_type = bool;
static constexpr object_type ucl_type = object_type::boolean;
// Create a boolean holding the value false. Throws std::system_error
// on failure.
boolean()
: boolean(false)
{
}
// Create a boolean holding a specific value. Throws std::system_error
// on failure.
explicit boolean(bool const value)
: object(noref, [&] {
auto *uobj = ::ucl_object_frombool(value);
if (uobj == nullptr)
throw std::system_error(std::make_error_code(sys_error()));
return uobj;
}())
{
}
// Create a new boolean from a UCL object. Throws type_mismatch
// on failure.
boolean(ref_t, ::ucl_object_t const *uobj)
: object(nihil::ucl::ref, ensure_ucl_type(uobj, boolean::ucl_type))
{
}
boolean(noref_t, ::ucl_object_t *uobj)
: object(nihil::ucl::noref, ensure_ucl_type(uobj, boolean::ucl_type))
{
}
// Return this object's value.
auto value(this boolean const &self) -> contained_type
{
auto v = contained_type{};
auto const *uobj = self.get_ucl_object();
if (::ucl_object_toboolean_safe(uobj, &v))
return v;
throw std::runtime_error("ucl_object_toboolean_safe failed");
}
private:
// Comparison operators.
[[nodiscard]] friend auto operator==(boolean const &a, boolean const &b) -> bool
{
return a.value() == b.value();
}
[[nodiscard]] friend auto
operator<=>(boolean const &a, boolean const &b) -> std::strong_ordering
{
return static_cast<int>(a.value()) <=> static_cast<int>(b.value());
}
[[nodiscard]] friend auto operator==(boolean const &a, contained_type const b) -> bool
{
return a.value() == b;
}
[[nodiscard]] friend auto
operator<=>(boolean const &a, contained_type const b) -> std::strong_ordering
{
return static_cast<int>(a.value()) <=> static_cast<int>(b);
}
};
// Boolean constructors. This returns an error instead of throwing.
export [[nodiscard]] auto
make_boolean(boolean::contained_type const value = false) -> std::expected<boolean, error>
{
if (auto *uobj = ::ucl_object_frombool(value); uobj == nullptr)
return error(errc::failed_to_create_object, error(sys_error()));
else
return boolean(noref, uobj);
}
} // namespace nihil::ucl
// std::formatter for a boolean. This provides the same format operations
// as std::formatter<bool>.
export template <>
struct std::formatter<nihil::ucl::boolean, char>
{
std::formatter<bool> base_formatter;
template <class ParseContext>
constexpr auto parse(ParseContext &ctx) -> ParseContext::iterator
{
return base_formatter.parse(ctx);
}
template <class FmtContext>
auto format(nihil::ucl::boolean const &o, FmtContext &ctx) const -> FmtContext::iterator
{
return base_formatter.format(o.value(), ctx);
}
};
|