24
24
25
25
#pragma once
26
26
27
- #include < string> // for string
28
- #include < utility> // for move
27
+ #include < optional> // for optional<>
28
+ #include < string> // for string
29
+ #include < type_traits> // for is_same_v<>, enable_if<>
30
+ #include < utility> // for move
29
31
30
- #include < boost/optional.hpp> // for optional<>
31
-
32
- #include < fable/schema/interface.hpp> // for Base<>, Box
33
- #include < fable/utility/boost_optional.hpp> // for to_json, from_json
32
+ #include < fable/schema/interface.hpp> // for Base<>, Box
33
+ #include < fable/utility/optional.hpp> // for adl_serializer<>
34
34
35
35
namespace fable {
36
36
namespace schema {
37
37
38
+ /* *
39
+ * Helper type trait class to use with std::enable_if and friends.
40
+ *
41
+ * The value `is_optional<T>::value` is true if T is one of:
42
+ * - std::optional
43
+ * - boost::optional, if boost_optional.hpp is included
44
+ *
45
+ * \see fable/schema/boost_optional.hpp
46
+ */
47
+ template <typename T>
48
+ struct is_optional : std::false_type {};
49
+
50
+ template <typename X>
51
+ struct is_optional <std::optional<X>> : std::true_type {};
52
+
53
+ /* *
54
+ * Optional de-/serializes a value that can be null.
55
+ *
56
+ * In a JSON object, a field that has the value null is not the
57
+ * same thing as a field that is missing!
58
+ *
59
+ * Optional is a template class that supports both:
60
+ * - std::optional
61
+ * - boost::optional, if boost_optional.hpp is included
62
+ */
38
63
template <typename T, typename P>
39
64
class Optional : public Base <Optional<T, P>> {
65
+ static_assert (is_optional<T>::value);
66
+
40
67
public: // Types and Constructors
41
- using Type = boost::optional<T>;
68
+ using Type = T;
69
+ using ValueType = typename Type::value_type;
42
70
using PrototypeSchema = std::remove_cv_t <std::remove_reference_t <P>>;
43
71
44
72
Optional (Type* ptr, std::string desc);
@@ -49,8 +77,8 @@ class Optional : public Base<Optional<T, P>> {
49
77
50
78
#if 0
51
79
// This is defined in: fable/schema/xmagic.hpp
52
- Optional(Type * ptr, std::string desc)
53
- : Optional(ptr, make_prototype<T >(), std::move(desc)) {}
80
+ Optional(T * ptr, std::string desc)
81
+ : Optional<T, P> (ptr, make_prototype<typename T::value_type >(), std::move(desc)) {}
54
82
#endif
55
83
56
84
public: // Overrides
@@ -92,15 +120,15 @@ class Optional : public Base<Optional<T, P>> {
92
120
93
121
Json serialize (const Type& x) const {
94
122
if (x) {
95
- return prototype_.serialize (x.get ());
123
+ return prototype_.serialize (x.value ());
96
124
} else {
97
125
return nullptr ;
98
126
}
99
127
}
100
128
101
129
Type deserialize (const Conf& c) const {
102
130
if (c->type () == JsonType::null) {
103
- return boost::none ;
131
+ return Type{} ;
104
132
}
105
133
return prototype_.deserialize (c);
106
134
}
@@ -112,8 +140,9 @@ class Optional : public Base<Optional<T, P>> {
112
140
Type* ptr_{nullptr };
113
141
};
114
142
115
- template <typename T, typename P, typename S>
116
- Optional<T, P> make_schema (boost::optional<T>* ptr, P&& prototype, S&& desc) {
143
+ // Define make_schema only for std::optional and boost::optional.
144
+ template <typename T, typename P, typename S, std::enable_if_t <is_optional<T>::value, bool > = true >
145
+ inline Optional<T, P> make_schema (T* ptr, P&& prototype, S&& desc) {
117
146
return Optional<T, P>(ptr, std::forward<P>(prototype), std::forward<S>(desc));
118
147
}
119
148
0 commit comments