diff options
Diffstat (limited to 'src/yajlpp/yajlpp_def.hh')
-rw-r--r-- | src/yajlpp/yajlpp_def.hh | 467 |
1 files changed, 386 insertions, 81 deletions
diff --git a/src/yajlpp/yajlpp_def.hh b/src/yajlpp/yajlpp_def.hh index 22454b1..7bcb687 100644 --- a/src/yajlpp/yajlpp_def.hh +++ b/src/yajlpp/yajlpp_def.hh @@ -241,11 +241,13 @@ struct json_path_handler : public json_path_handler_base { static int null_field_cb(yajlpp_parse_context* ypc) { + ypc->fill_in_source(); return ypc->ypc_current_handler->jph_null_cb(ypc); } static int bool_field_cb(yajlpp_parse_context* ypc, int val) { + ypc->fill_in_source(); return ypc->ypc_current_handler->jph_bool_cb(ypc, val); } @@ -253,20 +255,36 @@ struct json_path_handler : public json_path_handler_base { const unsigned char* str, size_t len) { - return ypc->ypc_current_handler->jph_str_cb(ypc, str, len); + ypc->fill_in_source(); + return ypc->ypc_current_handler->jph_str_cb( + ypc, string_fragment::from_bytes(str, len)); } static int int_field_cb(yajlpp_parse_context* ypc, long long val) { + ypc->fill_in_source(); return ypc->ypc_current_handler->jph_integer_cb(ypc, val); } static int dbl_field_cb(yajlpp_parse_context* ypc, double val) { + ypc->fill_in_source(); return ypc->ypc_current_handler->jph_double_cb(ypc, val); } template<typename T, typename U> + static inline U& get_field(T& input, std::shared_ptr<U>(T::*field)) + { + auto& ptr = input.*field; + + if (ptr.get() == nullptr) { + ptr = std::make_shared<U>(); + } + + return *ptr; + } + + template<typename T, typename U> static inline U& get_field(T& input, U(T::*field)) { return input.*field; @@ -366,11 +384,64 @@ struct json_path_handler : public json_path_handler_base { }; template<typename T, typename U> + struct LastIsVector<std::shared_ptr<std::vector<U>> T::*> { + using value_type = U; + static constexpr bool value = true; + }; + + template<typename T, typename U> struct LastIsVector<U T::*> { using value_type = void; static constexpr bool value = false; }; + template<typename T, typename... Args> + struct LastIsIntegerVector { + using value_type = typename LastIsIntegerVector<Args...>::value_type; + static constexpr bool value = LastIsIntegerVector<Args...>::value; + }; + + template<typename T, typename U> + struct LastIsIntegerVector<std::vector<U> T::*> { + using value_type = U; + static constexpr bool value + = std::is_integral<U>::value && !std::is_same<U, bool>::value; + }; + + template<typename T, typename U> + struct LastIsIntegerVector<U T::*> { + using value_type = void; + static constexpr bool value = false; + }; + + template<typename T, typename... Args> + struct LastIsMap { + using key_type = typename LastIsMap<Args...>::key_type; + using value_type = typename LastIsMap<Args...>::value_type; + static constexpr bool value = LastIsMap<Args...>::value; + }; + + template<typename T, typename K, typename U> + struct LastIsMap<std::shared_ptr<std::map<K, U>> T::*> { + using key_type = K; + using value_type = U; + static constexpr bool value = true; + }; + + template<typename T, typename K, typename U> + struct LastIsMap<std::map<K, U> T::*> { + using key_type = K; + using value_type = U; + static constexpr bool value = true; + }; + + template<typename T, typename U> + struct LastIsMap<U T::*> { + using key_type = void; + using value_type = void; + static constexpr bool value = false; + }; + template<typename T> static bool is_field_set(const nonstd::optional<T>& field) { @@ -434,15 +505,13 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); json_path_handler::get_field(obj, args...) - .emplace_back(std::move(value_str)); + .emplace_back(value_str.to_string()); return 1; }; @@ -450,10 +519,33 @@ struct json_path_handler : public json_path_handler_base { } template<typename... Args, + std::enable_if_t<LastIsIntegerVector<Args...>::value, bool> = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(int_field_cb); + this->jph_integer_cb + = [args...](yajlpp_parse_context* ypc, long long val) { + const auto* jph = ypc->ypc_current_handler; + auto* obj = ypc->ypc_obj_stack.top(); + + if (val < jph->jph_min_value) { + jph->report_min_value_error(ypc, val); + return 1; + } + + json_path_handler::get_field(obj, args...).emplace_back(val); + + return 1; + }; + return *this; + } + + template<typename... Args, std::enable_if_t<LastIsVector<Args...>::value, bool> = true, std::enable_if_t< !std::is_same<typename LastIsVector<Args...>::value_type, - std::string>::value, + std::string>::value + && !LastIsIntegerVector<Args...>::value, bool> = true> json_path_handler& for_field(Args... args) @@ -515,16 +607,37 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); auto key = ypc->get_path_fragment(-1); json_path_handler::get_field(obj, args...)[key] - = std::string((const char*) str, len); + = value_str.to_string(); return 1; }; + this->jph_path_provider = + [args...](void* root, std::vector<std::string>& paths_out) { + const auto& field = json_path_handler::get_field(root, args...); + + for (const auto& pair : field) { + paths_out.emplace_back(pair.first); + } + }; + this->jph_field_getter + = [args...](void* root, + nonstd::optional<std::string> name) -> const void* { + const auto& field = json_path_handler::get_field(root, args...); + if (!name) { + return &field; + } + + auto iter = field.find(name.value()); + if (iter == field.end()) { + return nullptr; + } + return (void*) &iter->second; + }; this->jph_gen_callback = [args...](yajlpp_gen_context& ygc, const json_path_handler_base& jph, yajl_gen handle) { @@ -555,6 +668,70 @@ struct json_path_handler : public json_path_handler_base { } template<typename... Args, + std::enable_if_t<LastIsMap<Args...>::value, bool> = true, + std::enable_if_t< + std::is_same<intern_string_t, + typename LastIsMap<Args...>::key_type>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->jph_path_provider = + [args...](void* root, std::vector<std::string>& paths_out) { + const auto& field = json_path_handler::get_field(root, args...); + + for (const auto& pair : field) { + paths_out.emplace_back(std::to_string(pair.first)); + } + }; + this->jph_obj_provider + = [args...](const yajlpp_provider_context& ypc, void* root) { + auto& field = json_path_handler::get_field(root, args...); + + return &(field[ypc.get_substr_i(0)]); + }; + return *this; + } + + template< + typename... Args, + std::enable_if_t<LastIsMap<Args...>::value, bool> = true, + std::enable_if_t< + std::is_same<std::string, + typename LastIsMap<Args...>::key_type>::value, + bool> + = true, + std::enable_if_t< + !std::is_same<json_any_t, + typename LastIsMap<Args...>::value_type>::value + && !std::is_same<std::string, + typename LastIsMap<Args...>::value_type>::value + && !std::is_same< + nonstd::optional<std::string>, + typename LastIsMap<Args...>::value_type>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->jph_path_provider = + [args...](void* root, std::vector<std::string>& paths_out) { + const auto& field = json_path_handler::get_field(root, args...); + + for (const auto& pair : field) { + paths_out.emplace_back(pair.first); + } + }; + this->jph_obj_provider + = [args...](const yajlpp_provider_context& ypc, void* root) { + auto& field = json_path_handler::get_field(root, args...); + auto key = ypc.get_substr(0); + + return &(field[key]); + }; + return *this; + } + + template<typename... Args, std::enable_if_t< LastIs<std::map<std::string, nonstd::optional<std::string>>, Args...>::value, @@ -564,13 +741,12 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { + const string_fragment& value_str) { auto obj = ypc->ypc_obj_stack.top(); auto key = ypc->get_path_fragment(-1); json_path_handler::get_field(obj, args...)[key] - = std::string((const char*) str, len); + = value_str.to_string(); return 1; }; @@ -642,13 +818,12 @@ struct json_path_handler : public json_path_handler_base { }; this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { + const string_fragment& value_str) { auto* obj = ypc->ypc_obj_stack.top(); auto key = ypc->get_path_fragment(-1); json_path_handler::get_field(obj, args...)[key] - = std::string((const char*) str, len); + = value_str.to_string(); return 1; }; @@ -691,14 +866,12 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); - json_path_handler::get_field(obj, args...) = std::move(value_str); + json_path_handler::get_field(obj, args...) = value_str.to_string(); return 1; }; @@ -738,23 +911,22 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; date_time_scanner dts; timeval tv{}; exttm tm; - if (dts.scan((char*) str, len, nullptr, &tm, tv) == nullptr) { - ypc->report_error( - lnav::console::user_message::error( - attr_line_t("unrecognized timestamp ") - .append_quoted( - string_fragment::from_bytes(str, len))) - .with_snippet(ypc->get_snippet()) - .with_help(jph->get_help_text(ypc))); + if (dts.scan(value_str.data(), value_str.length(), nullptr, &tm, tv) + == nullptr) + { + ypc->report_error(lnav::console::user_message::error( + attr_line_t("unrecognized timestamp ") + .append_quoted(value_str)) + .with_snippet(ypc->get_snippet()) + .with_help(jph->get_help_text(ypc))); } else { json_path_handler::get_field(obj, args...) = tv; } @@ -804,14 +976,20 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); - json_path_handler::get_field(obj, args...) = std::move(value_str); + json_path_handler::get_field(obj, args...) = value_str.to_string(); + + return 1; + }; + this->add_cb(null_field_cb); + this->jph_null_cb = [args...](yajlpp_parse_context* ypc) { + auto* obj = ypc->ypc_obj_stack.top(); + + json_path_handler::get_field(obj, args...) = nonstd::nullopt; return 1; }; @@ -858,11 +1036,9 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); auto& field = json_path_handler::get_field(obj, args...); @@ -870,7 +1046,7 @@ struct json_path_handler : public json_path_handler_base { field.pp_path = ypc->get_full_path(); field.pp_location.sl_source = ypc->ypc_source; field.pp_location.sl_line_number = ypc->get_line_number(); - field.pp_value = std::move(value_str); + field.pp_value = value_str.to_string(); return 1; }; @@ -897,6 +1073,10 @@ struct json_path_handler : public json_path_handler_base { return gen(field.pp_value); }; + this->jph_field_getter + = [args...](void* root, nonstd::optional<std::string> name) { + return (void*) &json_path_handler::get_field(root, args...); + }; return *this; } @@ -907,11 +1087,9 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); json_path_handler::get_field(obj, args...) @@ -945,6 +1123,60 @@ struct json_path_handler : public json_path_handler_base { return *this; } + template< + typename... Args, + std::enable_if_t< + LastIs<positioned_property<const date::time_zone*>, Args...>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(str_field_cb2); + this->jph_str_cb = [args...](yajlpp_parse_context* ypc, + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; + + try { + const auto* tz + = date::get_tzdb().locate_zone(value_str.to_string()); + auto& field = json_path_handler::get_field(obj, args...); + field.pp_path = ypc->get_full_path(); + field.pp_location.sl_source = ypc->ypc_source; + field.pp_location.sl_line_number = ypc->get_line_number(); + field.pp_value = tz; + } catch (const std::runtime_error& e) { + jph->report_tz_error(ypc, value_str.to_string(), e.what()); + } + + return 1; + }; + this->jph_gen_callback = [args...](yajlpp_gen_context& ygc, + const json_path_handler_base& jph, + yajl_gen handle) { + const auto& field = json_path_handler::get_field( + ygc.ygc_obj_stack.top(), args...); + + if (!ygc.ygc_default_stack.empty()) { + const auto& field_def = json_path_handler::get_field( + ygc.ygc_default_stack.top(), args...); + + if (field.pp_value == field_def.pp_value) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field.pp_value->name()); + }; + return *this; + } + template<typename... Args, std::enable_if_t< LastIs<positioned_property<intern_string_t>, Args...>::value, @@ -954,11 +1186,9 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto value_str = std::string((const char*) str, len); - auto jph = ypc->ypc_current_handler; + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* jph = ypc->ypc_current_handler; jph->validate_string(*ypc, value_str); auto& field = json_path_handler::get_field(obj, args...); @@ -997,7 +1227,7 @@ struct json_path_handler : public json_path_handler_base { template<typename> struct int_ { - typedef int type; + using type = int; }; template< typename C, @@ -1009,11 +1239,10 @@ struct json_path_handler : public json_path_handler_base { json_path_handler& for_field(Args... args, T C::*ptr_arg) { this->add_cb(str_field_cb2); - this->jph_str_cb = [args..., ptr_arg](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { + this->jph_str_cb = [args..., ptr_arg]( + yajlpp_parse_context* ypc, + const string_fragment& value_frag) { auto* obj = ypc->ypc_obj_stack.top(); - auto value_frag = string_fragment::from_bytes(str, len); const auto* jph = ypc->ypc_current_handler; auto loc = source_location{ypc->ypc_source, ypc->get_line_number()}; @@ -1028,6 +1257,30 @@ struct json_path_handler : public json_path_handler_base { return 1; }; + this->jph_gen_callback + = [args..., ptr_arg](yajlpp_gen_context& ygc, + const json_path_handler_base& jph, + yajl_gen handle) { + const auto& field = json_path_handler::get_field( + ygc.ygc_obj_stack.top(), args..., ptr_arg); + + if (!ygc.ygc_default_stack.empty()) { + const auto& field_def = json_path_handler::get_field( + ygc.ygc_default_stack.top(), args..., ptr_arg); + + if (field.pp_value == field_def.pp_value) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field.to_string()); + }; return *this; } @@ -1038,7 +1291,7 @@ struct json_path_handler : public json_path_handler_base { this->add_cb(int_field_cb); this->jph_integer_cb = [args...](yajlpp_parse_context* ypc, long long val) { - auto jph = ypc->ypc_current_handler; + const auto* jph = ypc->ypc_current_handler; auto* obj = ypc->ypc_obj_stack.top(); if (val < jph->jph_min_value) { @@ -1091,7 +1344,7 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(dbl_field_cb); this->jph_double_cb = [args...](yajlpp_parse_context* ypc, double val) { - auto jph = ypc->ypc_current_handler; + const auto* jph = ypc->ypc_current_handler; auto* obj = ypc->ypc_obj_stack.top(); if (val < jph->jph_min_value) { @@ -1146,18 +1399,16 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto handler = ypc->ypc_current_handler; - auto parse_res = relative_time::from_str( - string_fragment::from_bytes(str, len)); + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* handler = ypc->ypc_current_handler; + auto parse_res = relative_time::from_str(value_str); if (parse_res.isErr()) { auto parse_error = parse_res.unwrapErr(); - auto value_str = std::string((const char*) str, len); - handler->report_duration_error(ypc, value_str, parse_error); + handler->report_duration_error( + ypc, value_str.to_string(), parse_error); return 1; } @@ -1204,18 +1455,16 @@ struct json_path_handler : public json_path_handler_base { { this->add_cb(str_field_cb2); this->jph_str_cb = [args...](yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) { - auto obj = ypc->ypc_obj_stack.top(); - auto handler = ypc->ypc_current_handler; - auto res = handler->to_enum_value(string_fragment(str, 0, len)); + const string_fragment& value_str) { + auto* obj = ypc->ypc_obj_stack.top(); + const auto* handler = ypc->ypc_current_handler; + auto res = handler->to_enum_value(value_str); if (res) { json_path_handler::get_field(obj, args...) = (typename LastIsEnum<Args...>::value_type) res.value(); } else { - handler->report_enum_error(ypc, - std::string((const char*) str, len)); + handler->report_enum_error(ypc, value_str.to_string()); } return 1; @@ -1325,11 +1574,34 @@ public: return *this; } + Result<void, std::vector<lnav::console::user_message>> consume( + const string_fragment& json) + { + if (this->yp_parse_context.parse(json) == yajl_status_ok) { + if (this->yp_errors.empty()) { + return Ok(); + } + } + + return Err(std::move(this->yp_errors)); + } + + Result<T, std::vector<lnav::console::user_message>> complete() + { + if (this->yp_parse_context.complete_parse() == yajl_status_ok) { + return Ok(std::move(this->yp_obj)); + } + + return Err(std::move(this->yp_errors)); + } + Result<T, std::vector<lnav::console::user_message>> of( const string_fragment& json) { if (this->yp_parse_context.parse_doc(json)) { - return Ok(std::move(this->yp_obj)); + if (this->yp_errors.empty()) { + return Ok(std::move(this->yp_obj)); + } } return Err(std::move(this->yp_errors)); @@ -1343,6 +1615,34 @@ private: }; template<typename T> +struct typed_json_path_container; + +template<typename T> +struct yajlpp_formatter { + const T& yf_obj; + const typed_json_path_container<T>& yf_container; + yajlpp_gen yf_gen; + + template<typename... Args> + yajlpp_formatter<T> with_config(Args... args) && + { + yajl_gen_config(this->yf_gen.get_handle(), args...); + + return std::move(*this); + } + + std::string to_string() && + { + yajlpp_gen_context ygc(this->yf_gen, this->yf_container); + ygc.template with_obj(this->yf_obj); + ygc.ygc_depth = 1; + ygc.gen(); + + return this->yf_gen.to_string_fragment().to_string(); + } +}; + +template<typename T> struct typed_json_path_container : public json_path_container { typed_json_path_container(std::initializer_list<json_path_handler> children) : json_path_container(children) @@ -1366,6 +1666,11 @@ struct typed_json_path_container : public json_path_container { return yajlpp_parser<T>{src, this}; } + yajlpp_formatter<T> formatter_for(const T& obj) const + { + return yajlpp_formatter<T>{obj, *this}; + } + std::string to_string(const T& obj) const { yajlpp_gen gen; |