aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl/boolean.ccm
blob: 4cacdc4306636493646e2837d6faccab79d26230 (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
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);
	}
};