1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in 2 // the main distribution directory for license terms and copyright or visit 3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE. 4 5 #pragma once 6 7 #include <type_traits> 8 #include <utility> 9 10 #include "caf/detail/as_mutable_ref.hpp" 11 #include "caf/detail/core_export.hpp" 12 #include "caf/error.hpp" 13 #include "caf/inspector_access.hpp" 14 #include "caf/string_view.hpp" 15 16 namespace caf { 17 18 /// Base type for inspectors that load objects from some input source. Deriving 19 /// from this class enables the inspector DSL. 20 /// @note The derived type still needs to provide an `object()` member function 21 /// for the DSL. 22 class CAF_CORE_EXPORT load_inspector { 23 public: 24 // -- member types ----------------------------------------------------------- 25 26 using result_type [[deprecated("inspectors always return bool")]] = bool; 27 28 // -- constants -------------------------------------------------------------- 29 30 /// Enables dispatching on the inspector type. 31 static constexpr bool is_loading = true; 32 33 // -- constructors, destructors, and assignment operators -------------------- 34 35 virtual ~load_inspector(); 36 37 // -- properties ------------------------------------------------------------- 38 set_error(error stop_reason)39 void set_error(error stop_reason) { 40 err_ = std::move(stop_reason); 41 } 42 43 template <class... Ts> emplace_error(Ts &&...xs)44 void emplace_error(Ts&&... xs) { 45 err_ = make_error(std::forward<Ts>(xs)...); 46 } 47 get_error() const48 const error& get_error() const noexcept { 49 return err_; 50 } 51 move_error()52 error&& move_error() noexcept { 53 return std::move(err_); 54 } 55 56 // -- DSL types for regular fields ------------------------------------------- 57 58 template <class T, class U, class Predicate> 59 struct field_with_invariant_and_fallback_t { 60 string_view field_name; 61 T* val; 62 U fallback; 63 Predicate predicate; 64 65 template <class Inspector> operator ()caf::load_inspector::field_with_invariant_and_fallback_t66 bool operator()(Inspector& f) { 67 auto reset = [this] { *val = std::move(fallback); }; 68 return detail::load_field(f, field_name, *val, predicate, 69 detail::always_true, reset); 70 } 71 }; 72 73 template <class T, class U> 74 struct field_with_fallback_t { 75 string_view field_name; 76 T* val; 77 U fallback; 78 79 template <class Inspector> operator ()caf::load_inspector::field_with_fallback_t80 bool operator()(Inspector& f) { 81 auto reset = [this] { *val = std::move(fallback); }; 82 return detail::load_field(f, field_name, *val, detail::always_true, 83 detail::always_true, reset); 84 } 85 86 template <class Predicate> invariantcaf::load_inspector::field_with_fallback_t87 auto invariant(Predicate predicate) && { 88 return field_with_invariant_and_fallback_t<T, U, Predicate>{ 89 field_name, 90 val, 91 std::move(fallback), 92 std::move(predicate), 93 }; 94 } 95 }; 96 97 template <class T, class Predicate> 98 struct field_with_invariant_t { 99 string_view field_name; 100 T* val; 101 Predicate predicate; 102 103 template <class Inspector> operator ()caf::load_inspector::field_with_invariant_t104 bool operator()(Inspector& f) { 105 return detail::load_field(f, field_name, *val, predicate, 106 detail::always_true); 107 } 108 109 template <class U> fallbackcaf::load_inspector::field_with_invariant_t110 auto fallback(U value) && { 111 return field_with_invariant_and_fallback_t<T, U, Predicate>{ 112 field_name, 113 val, 114 std::move(value), 115 std::move(predicate), 116 }; 117 } 118 }; 119 120 template <class T> 121 struct field_t { 122 string_view field_name; 123 T* val; 124 125 template <class Inspector> operator ()caf::load_inspector::field_t126 bool operator()(Inspector& f) { 127 return detail::load_field(f, field_name, *val, detail::always_true, 128 detail::always_true); 129 } 130 131 template <class U> fallbackcaf::load_inspector::field_t132 auto fallback(U value) && { 133 return field_with_fallback_t<T, U>{field_name, val, std::move(value)}; 134 } 135 136 template <class Predicate> invariantcaf::load_inspector::field_t137 auto invariant(Predicate predicate) && { 138 return field_with_invariant_t<T, Predicate>{ 139 field_name, 140 val, 141 std::move(predicate), 142 }; 143 } 144 }; 145 146 // -- DSL types for virtual fields (getter and setter access) ---------------- 147 148 template <class T, class Set, class U, class Predicate> 149 struct virt_field_with_invariant_and_fallback_t { 150 string_view field_name; 151 Set set; 152 U fallback; 153 Predicate predicate; 154 155 template <class Inspector> operator ()caf::load_inspector::virt_field_with_invariant_and_fallback_t156 bool operator()(Inspector& f) { 157 auto tmp = T{}; 158 auto sync = detail::bind_setter(f, set, tmp); 159 auto reset = [this] { set(std::move(fallback)); }; 160 return detail::load_field(f, field_name, tmp, predicate, sync, reset); 161 } 162 }; 163 164 template <class T, class Set, class U> 165 struct virt_field_with_fallback_t { 166 string_view field_name; 167 Set set; 168 U fallback; 169 170 template <class Inspector> operator ()caf::load_inspector::virt_field_with_fallback_t171 bool operator()(Inspector& f) { 172 auto tmp = T{}; 173 auto sync = detail::bind_setter(f, set, tmp); 174 auto reset = [this] { set(std::move(fallback)); }; 175 return detail::load_field(f, field_name, tmp, detail::always_true, sync, 176 reset); 177 } 178 179 template <class Predicate> invariantcaf::load_inspector::virt_field_with_fallback_t180 auto invariant(Predicate predicate) && { 181 return virt_field_with_invariant_and_fallback_t<T, Set, U, Predicate>{ 182 field_name, 183 std::move(set), 184 std::move(fallback), 185 std::move(predicate), 186 }; 187 } 188 }; 189 190 template <class T, class Set, class Predicate> 191 struct virt_field_with_invariant_t { 192 string_view field_name; 193 Set set; 194 Predicate predicate; 195 196 template <class Inspector> operator ()caf::load_inspector::virt_field_with_invariant_t197 bool operator()(Inspector& f) { 198 auto tmp = T{}; 199 auto sync = detail::bind_setter(f, set, tmp); 200 return detail::load_field(f, field_name, tmp, predicate, sync); 201 } 202 203 template <class U> fallbackcaf::load_inspector::virt_field_with_invariant_t204 auto fallback(U value) && { 205 return virt_field_with_invariant_and_fallback_t<T, Set, U, Predicate>{ 206 field_name, 207 std::move(set), 208 std::move(value), 209 std::move(predicate), 210 }; 211 } 212 }; 213 214 template <class T, class Set> 215 struct virt_field_t { 216 string_view field_name; 217 Set set; 218 219 template <class Inspector> operator ()caf::load_inspector::virt_field_t220 bool operator()(Inspector& f) { 221 auto tmp = T{}; 222 auto sync = detail::bind_setter(f, set, tmp); 223 return detail::load_field(f, field_name, tmp, detail::always_true, sync); 224 } 225 226 template <class U> fallbackcaf::load_inspector::virt_field_t227 auto fallback(U value) && { 228 return virt_field_with_fallback_t<T, Set, U>{ 229 field_name, 230 std::move(set), 231 std::move(value), 232 }; 233 } 234 235 template <class Predicate> invariantcaf::load_inspector::virt_field_t236 auto invariant(Predicate predicate) && { 237 return virt_field_with_invariant_t<T, Set, Predicate>{ 238 field_name, 239 std::move(set), 240 std::move(predicate), 241 }; 242 } 243 }; 244 245 template <class T, class Reset, class Set> 246 struct optional_virt_field_t { 247 string_view field_name; 248 Reset reset; 249 Set set; 250 251 template <class Inspector> operator ()caf::load_inspector::optional_virt_field_t252 bool operator()(Inspector& f) { 253 auto tmp = T{}; 254 auto sync = detail::bind_setter(f, set, tmp); 255 return detail::load_field(f, field_name, tmp, detail::always_true, sync, 256 reset); 257 } 258 }; 259 260 // -- DSL type for the object ------------------------------------------------ 261 262 template <class Inspector, class LoadCallback> 263 struct object_with_load_callback_t { 264 type_id_t object_type; 265 string_view object_name; 266 Inspector* f; 267 LoadCallback load_callback; 268 269 template <class... Fields> fieldscaf::load_inspector::object_with_load_callback_t270 bool fields(Fields&&... fs) { 271 using load_callback_result = decltype(load_callback()); 272 if (!(f->begin_object(object_type, object_name) && (fs(*f) && ...))) 273 return false; 274 if constexpr (std::is_same<load_callback_result, bool>::value) { 275 if (!load_callback()) { 276 f->set_error(sec::load_callback_failed); 277 return false; 278 } 279 } else { 280 if (auto err = load_callback()) { 281 f->set_error(std::move(err)); 282 return false; 283 } 284 } 285 return f->end_object(); 286 } 287 pretty_namecaf::load_inspector::object_with_load_callback_t288 auto pretty_name(string_view name) && { 289 return object_t{object_type, name, f}; 290 } 291 292 template <class F> on_savecaf::load_inspector::object_with_load_callback_t293 object_with_load_callback_t&& on_save(F&&) && { 294 return std::move(*this); 295 } 296 }; 297 298 template <class Inspector> 299 struct object_t { 300 type_id_t object_type; 301 string_view object_name; 302 Inspector* f; 303 304 template <class... Fields> fieldscaf::load_inspector::object_t305 bool fields(Fields&&... fs) { 306 return f->begin_object(object_type, object_name) // 307 && (fs(*f) && ...) // 308 && f->end_object(); 309 } 310 pretty_namecaf::load_inspector::object_t311 auto pretty_name(string_view name) && { 312 return object_t{object_type, name, f}; 313 } 314 315 template <class F> on_savecaf::load_inspector::object_t316 object_t&& on_save(F&&) && { 317 return std::move(*this); 318 } 319 320 template <class F> on_loadcaf::load_inspector::object_t321 auto on_load(F fun) && { 322 return object_with_load_callback_t<Inspector, F>{ 323 object_type, 324 object_name, 325 f, 326 std::move(fun), 327 }; 328 } 329 }; 330 331 // -- factory functions ------------------------------------------------------ 332 333 template <class T> field(string_view name,T & x)334 static auto field(string_view name, T& x) { 335 static_assert(!std::is_const<T>::value); 336 return field_t<T>{name, &x}; 337 } 338 339 template <class Get, class Set> field(string_view name,Get get,Set set)340 static auto field(string_view name, Get get, Set set) { 341 using field_type = std::decay_t<decltype(get())>; 342 using setter_result = decltype(set(std::declval<field_type&&>())); 343 if constexpr (std::is_same<setter_result, error>::value 344 || std::is_same<setter_result, bool>::value) { 345 return virt_field_t<field_type, Set>{name, std::move(set)}; 346 } else { 347 static_assert(std::is_same<setter_result, void>::value, 348 "a setter must return caf::error, bool or void"); 349 auto set_fun = [f{std::move(set)}](field_type&& val) { 350 f(std::move(val)); 351 return true; 352 }; 353 return virt_field_t<field_type, decltype(set_fun)>{name, 354 std::move(set_fun)}; 355 } 356 } 357 358 template <class IsPresent, class Get, class Reset, class Set> 359 static auto field(string_view name,IsPresent &&,Get && get,Reset reset,Set set)360 field(string_view name, IsPresent&&, Get&& get, Reset reset, Set set) { 361 using field_type = std::decay_t<decltype(get())>; 362 using setter_result = decltype(set(std::declval<field_type&&>())); 363 if constexpr (std::is_same<setter_result, error>::value 364 || std::is_same<setter_result, bool>::value) { 365 return optional_virt_field_t<field_type, Reset, Set>{name, 366 std::move(reset), 367 std::move(set)}; 368 } else { 369 static_assert(std::is_same<setter_result, void>::value, 370 "a setter must return caf::error, bool or void"); 371 auto set_fun = [f{std::move(set)}](field_type&& val) { 372 f(std::move(val)); 373 return true; 374 }; 375 return optional_virt_field_t<field_type, Reset, Set>{name, 376 std::move(reset), 377 std::move(set_fun)}; 378 } 379 } 380 381 protected: 382 error err_; 383 }; 384 385 } // namespace caf 386