37
37
namespace fable {
38
38
namespace schema {
39
39
40
- using BoxPairList = std::initializer_list<std::pair<std::string const , Box>>;
41
- using BoxMap = std::map<std::string, Box>;
40
+ /* *
41
+ * PropertyList is mainly used in constructors to enable the use of initializer
42
+ * list.
43
+ *
44
+ * \example
45
+ * Given the following constructor declaration:
46
+ *
47
+ * Struct(PropertyList<> props);
48
+ *
49
+ * Struct can be instantiated then like so:
50
+ *
51
+ * return Struct{
52
+ * {"prop_a", make_schema(...)},
53
+ * {"prop_b", make_schema(...)},
54
+ * };
55
+ */
56
+ template <typename S = Box>
57
+ using PropertyList = std::initializer_list<std::pair<std::string const , S>>;
42
58
43
- template <typename T>
44
- using is_properties_t =
45
- std::enable_if_t <std::is_same<BoxPairList, T>::value || std::is_same<BoxMap, T>::value, int >;
59
+ template <typename T, typename S = Box>
60
+ using enable_if_property_list_t = std::enable_if_t <std::is_same<PropertyList<S>, T>::value>;
46
61
47
62
/* *
48
63
* Struct maintains a key-value mapping, where the list of keys is usually
@@ -53,53 +68,111 @@ using is_properties_t =
53
68
*
54
69
* This should not be confused with the Map type.
55
70
*
56
- * \see fable/schema/map.hpp
71
+ * \see fable/schema/map.hpp
57
72
*/
58
73
class Struct : public Base <Struct> {
59
74
public: // Constructors
60
75
explicit Struct (std::string&& desc = " " ) : Base(JsonType::object, std::move(desc)) {}
61
76
62
- Struct (std::string&& desc, BoxPairList props);
63
- Struct (std::string&& desc, BoxMap&& props);
64
- Struct (std::string&& desc, const Struct& base, BoxPairList props);
65
- Struct (std::string&& desc, const Struct& base, BoxMap&& props);
66
- Struct (std::string&& desc, const Box& base, BoxPairList props);
67
- Struct (std::string&& desc, const Box& base, BoxMap&& props);
77
+ Struct (std::string&& desc, PropertyList<Box> props) : Base(JsonType::object, std::move(desc)) {
78
+ set_properties (props);
79
+ }
68
80
69
- Struct (BoxPairList props) : Struct(" " , std::move(props)) {} // NOLINT
70
- Struct (BoxMap&& props) : Struct(" " , std::move(props)) {} // NOLINT
71
- Struct (const Struct& base, BoxPairList props) : Struct(" " , base, std::move(props)) {}
72
- Struct (const Struct& base, BoxMap&& props) : Struct(" " , base, std::move(props)) {}
73
- Struct (const Box& base, BoxPairList props) : Struct(" " , base, std::move(props)) {}
74
- Struct (const Box& base, BoxMap&& props) : Struct(" " , base, std::move(props)) {}
81
+ Struct (PropertyList<Box> props) : Struct(" " , props) {} // NOLINT
82
+
83
+ // Inheriting constructors
84
+ /* *
85
+ * Instantiate a Struct with a base Schema, which should also be a Struct,
86
+ * then extend it with the property list.
87
+ *
88
+ * This is particularly useful when the Confable is inheriting from a base
89
+ * class:
90
+ *
91
+ * struct Sub : public Base {
92
+ * std::string member;
93
+ * CONFABLE_SCHEMA(Sub) {
94
+ * return Struct{
95
+ * Base::schema_impl(),
96
+ * {
97
+ * {"member", make_schema(&member, "important addition")},
98
+ * }
99
+ * };
100
+ * }
101
+ * };
102
+ *
103
+ * Warning: When implementing schema_impl, for example with CONFABLE_SCHEMA,
104
+ * it is absolutely important that you _not_ call Base::schema(), as this
105
+ * will internally call this->schema_impl(), which will lead to an
106
+ * infinite recursion! Instead, call Base::schema_impl().
107
+ */
108
+ Struct (std::string&& desc, const Box& base, PropertyList<Box> props)
109
+ : Struct(*base.template as<Struct>()) {
110
+ desc_ = std::move (desc);
111
+ set_properties (props);
112
+ }
113
+
114
+ Struct (const Box& base, PropertyList<Box> props) : Struct(" " , base, props) {}
75
115
76
116
public: // Special
77
117
/* *
78
118
* Set the property to this schema.
79
119
*
80
120
* - This overwrites any already existing field of the same key.
81
- * - Meant to be used during construction.
82
121
*/
83
- Struct property (std::string&& key, Box&& s) &&;
84
- Struct property (const std::string& key, Box&& s) &&;
85
- void set_property (const std::string& key, const Box& s);
122
+ void set_property (const std::string& key, Box&& s);
123
+
124
+ Struct property (const std::string& key, Box&& s) && {
125
+ set_property (key, std::move (s));
126
+ return std::move (*this );
127
+ }
86
128
87
129
/* *
88
- * Set whether all entries are required .
130
+ * Set all properties .
89
131
*
90
- * - The default is false.
91
- * - Meant to be used during construction.
132
+ * - This overwrites any already existing property of the same key.
92
133
*/
93
- Struct require_all () && ;
134
+ void set_properties (PropertyList<Box> props) ;
94
135
95
136
/* *
96
- * Set which entries are required.
137
+ * Add the properties from s to this schema.
138
+ *
139
+ * - This will overwrite any existing properties.
97
140
*/
98
- Struct require (std::initializer_list<std::string> init) {
99
- properties_required_ = init;
141
+ void set_properties_from (const Struct& s) { set_properties (s.properties_ ); }
142
+
143
+ void set_properties_from (const Box& s) { set_properties_from (*s.template as <Struct>()); }
144
+
145
+ template <typename T, typename = enable_if_confable_t <T>>
146
+ void set_properties_from (const T* x) {
147
+ set_properties_from (x->schema ());
148
+ }
149
+
150
+ template <typename T>
151
+ Struct properties_from (const T x) {
152
+ set_properties_from (x);
100
153
return std::move (*this );
101
154
}
102
155
156
+ /* *
157
+ * Set which entries are required.
158
+ *
159
+ * - Complexity: O(n*m) with n the number of current properties and
160
+ * m the number of properties in init.
161
+ */
162
+ void set_require (std::initializer_list<std::string> init);
163
+ Struct require (std::initializer_list<std::string> init) &&;
164
+
165
+ /* *
166
+ * Set whether all entries are required.
167
+ *
168
+ * - The default is false.
169
+ * - Meant to be used during construction.
170
+ * - This will only act on properties that exist at the time that this is
171
+ * called.
172
+ */
173
+ void set_require_all ();
174
+ Struct require_all () &&;
175
+
103
176
/* *
104
177
* Set whether to tolerate unknown fields in this entry.
105
178
*
@@ -111,11 +184,16 @@ class Struct : public Base<Struct> {
111
184
return std::move (*this );
112
185
}
113
186
114
- template <typename T, std:: enable_if_t <std::is_base_of<Interface, T>::value, int > = 0 >
115
- Struct additional_properties (const T & s) && {
187
+ template <typename S, typename = enable_if_schema_t <S> >
188
+ void set_additional_properties (const S & s) {
116
189
additional_properties_ = true ;
117
- additional_prototype_ = s.clone ();
190
+ additional_prototype_. reset ( s.clone () );
118
191
additional_prototype_->reset_ptr ();
192
+ }
193
+
194
+ template <typename S, typename = enable_if_schema_t <S>>
195
+ Struct additional_properties (const S& s) && {
196
+ set_additional_properties (s);
119
197
return std::move (*this );
120
198
}
121
199
@@ -130,29 +208,32 @@ class Struct : public Base<Struct> {
130
208
void to_json (Json& j) const override ;
131
209
void from_conf (const Conf& c) override ;
132
210
211
+ private:
212
+ void set_properties (const std::map<std::string, Box>& props);
213
+
133
214
private:
134
215
std::map<std::string, Box> properties_{};
135
216
std::vector<std::string> properties_required_{};
136
217
std::shared_ptr<Interface> additional_prototype_{};
137
218
bool additional_properties_{false };
138
219
};
139
220
140
- template <typename T, is_properties_t <T> = 0 >
221
+ template <typename T, typename = enable_if_property_list_t <T> >
141
222
inline Struct make_schema (T&& props) {
142
223
return Struct (std::forward<T>(props));
143
224
}
144
225
145
- template <typename T, is_properties_t <T> = 0 >
226
+ template <typename T, typename = enable_if_property_list_t <T> >
146
227
inline Struct make_schema (std::string&& desc, T&& props) {
147
228
return Struct (std::move (desc), std::forward<T>(props));
148
229
}
149
230
150
- template <typename T, is_properties_t <T> = 0 >
231
+ template <typename T, typename = enable_if_property_list_t <T> >
151
232
inline Struct make_schema (std::string&& desc, const Box& base, T&& props) {
152
233
return Struct (std::move (desc), base, std::forward<T>(props));
153
234
}
154
235
155
- template <typename T, is_properties_t <T> = 0 >
236
+ template <typename T, typename = enable_if_property_list_t <T> >
156
237
inline Struct make_schema (std::string&& desc, const Struct& base, T&& props) {
157
238
return Struct (std::move (desc), base, std::forward<T>(props));
158
239
}
0 commit comments