From 5068d34c08f951a7ea6257d305a1627b09a95817 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 19:44:55 +0200 Subject: Adding upstream version 0.11.1. Signed-off-by: Daniel Baumann --- src/yajlpp/yajlpp_def.hh | 1388 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1388 insertions(+) create mode 100644 src/yajlpp/yajlpp_def.hh (limited to 'src/yajlpp/yajlpp_def.hh') diff --git a/src/yajlpp/yajlpp_def.hh b/src/yajlpp/yajlpp_def.hh new file mode 100644 index 0000000..b511fa9 --- /dev/null +++ b/src/yajlpp/yajlpp_def.hh @@ -0,0 +1,1388 @@ +/** + * Copyright (c) 2018, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file yajlpp_def.hh + */ + +#ifndef yajlpp_def_hh +#define yajlpp_def_hh + +#include + +#include "base/date_time_scanner.hh" +#include "base/time_util.hh" +#include "config.h" +#include "mapbox/variant.hpp" +#include "relative_time.hh" +#include "yajlpp.hh" + +struct json_null_t { + bool operator==(const json_null_t& other) const { return true; } +}; + +using json_any_t + = mapbox::util::variant; + +struct json_path_container; + +struct json_path_handler : public json_path_handler_base { + template + json_path_handler(P path, int (*null_func)(yajlpp_parse_context*)) + : json_path_handler_base(path) + { + this->jph_callbacks.yajl_null = (int (*)(void*)) null_func; + } + + template + json_path_handler(P path, int (*bool_func)(yajlpp_parse_context*, int)) + : json_path_handler_base(path) + { + this->jph_callbacks.yajl_boolean = (int (*)(void*, int)) bool_func; + } + + template + json_path_handler(P path, int (*int_func)(yajlpp_parse_context*, long long)) + : json_path_handler_base(path) + { + this->jph_callbacks.yajl_integer = (int (*)(void*, long long)) int_func; + } + + template + json_path_handler(P path, int (*double_func)(yajlpp_parse_context*, double)) + : json_path_handler_base(path) + { + this->jph_callbacks.yajl_double = (int (*)(void*, double)) double_func; + } + + template + json_path_handler(P path) : json_path_handler_base(path) + { + } + + template + json_path_handler(P path, + int (*str_func)(yajlpp_parse_context*, + const unsigned char*, + size_t)) + : json_path_handler_base(path) + { + this->jph_callbacks.yajl_string + = (int (*)(void*, const unsigned char*, size_t)) str_func; + } + + json_path_handler(const std::string& path, + const std::shared_ptr& re) + : json_path_handler_base(path, re) + { + } + + json_path_handler& add_cb(int (*null_func)(yajlpp_parse_context*)) + { + this->jph_callbacks.yajl_null = (int (*)(void*)) null_func; + return *this; + } + + json_path_handler& add_cb(int (*bool_func)(yajlpp_parse_context*, int)) + { + this->jph_callbacks.yajl_boolean = (int (*)(void*, int)) bool_func; + return *this; + } + + json_path_handler& add_cb(int (*int_func)(yajlpp_parse_context*, long long)) + { + this->jph_callbacks.yajl_integer = (int (*)(void*, long long)) int_func; + return *this; + } + + json_path_handler& add_cb(int (*double_func)(yajlpp_parse_context*, double)) + { + this->jph_callbacks.yajl_double = (int (*)(void*, double)) double_func; + return *this; + } + + json_path_handler& add_cb(int (*str_func)(yajlpp_parse_context*, + const unsigned char*, + size_t)) + { + this->jph_callbacks.yajl_string + = (int (*)(void*, const unsigned char*, size_t)) str_func; + return *this; + } + + json_path_handler& with_synopsis(const char* synopsis) + { + this->jph_synopsis = synopsis; + return *this; + } + + json_path_handler& with_description(const char* description) + { + this->jph_description = description; + return *this; + } + + json_path_handler& with_min_length(size_t len) + { + this->jph_min_length = len; + return *this; + } + + json_path_handler& with_max_length(size_t len) + { + this->jph_max_length = len; + return *this; + } + + json_path_handler& with_enum_values(const enum_value_t values[]) + { + this->jph_enum_values = values; + return *this; + } + + template + json_path_handler& with_pattern(const T (&re)[N]) + { + this->jph_pattern_re = re; + this->jph_pattern = lnav::pcre2pp::code::from_const(re).to_shared(); + return *this; + } + + json_path_handler& with_min_value(long long val) + { + this->jph_min_value = val; + return *this; + } + + template + json_path_handler& with_obj_provider( + R* (*provider)(const yajlpp_provider_context& pc, T* root)) + { + this->jph_obj_provider + = [provider](const yajlpp_provider_context& ypc, void* root) { + return (R*) provider(ypc, (T*) root); + }; + return *this; + } + + template + json_path_handler& with_size_provider(size_t (*provider)(const R* root)) + { + this->jph_size_provider + = [provider](const void* root) { return provider((R*) root); }; + return *this; + } + + template + json_path_handler& with_path_provider( + void (*provider)(T* root, std::vector& paths_out)) + { + this->jph_path_provider + = [provider](void* root, std::vector& paths_out) { + provider((T*) root, paths_out); + }; + return *this; + } + + template + json_path_handler& with_obj_deleter( + void (*provider)(const yajlpp_provider_context& pc, T* root)) + { + this->jph_obj_deleter + = [provider](const yajlpp_provider_context& ypc, void* root) { + provider(ypc, (T*) root); + }; + return *this; + } + + static int null_field_cb(yajlpp_parse_context* ypc) + { + return ypc->ypc_current_handler->jph_null_cb(ypc); + } + + static int bool_field_cb(yajlpp_parse_context* ypc, int val) + { + return ypc->ypc_current_handler->jph_bool_cb(ypc, val); + } + + static int str_field_cb2(yajlpp_parse_context* ypc, + const unsigned char* str, + size_t len) + { + return ypc->ypc_current_handler->jph_str_cb(ypc, str, len); + } + + static int int_field_cb(yajlpp_parse_context* ypc, long long val) + { + return ypc->ypc_current_handler->jph_integer_cb(ypc, val); + } + + static int dbl_field_cb(yajlpp_parse_context* ypc, double val) + { + return ypc->ypc_current_handler->jph_double_cb(ypc, val); + } + + template + static inline U& get_field(T& input, U(T::*field)) + { + return input.*field; + } + + template + static inline auto get_field(T& input, U(T::*field), V... args) + -> decltype(get_field(input.*field, args...)) + { + return get_field(input.*field, args...); + } + + template + static inline auto get_field(void* input, U(T::*field), V... args) + -> decltype(get_field(*((T*) input), field, args...)) + { + return get_field(*((T*) input), field, args...); + } + + template + struct LastIs { + static constexpr bool value = LastIs::value; + }; + + template + struct LastIs { + static constexpr bool value = false; + }; + + template + struct LastIs { + static constexpr bool value = true; + }; + + template + struct LastIsEnum { + using value_type = typename LastIsEnum::value_type; + static constexpr bool value = LastIsEnum::value; + }; + + template + struct LastIsEnum { + using value_type = U; + + static constexpr bool value = std::is_enum::value; + }; + + template + struct LastIsEnum T::*> { + using value_type = U; + + static constexpr bool value = std::is_enum::value; + }; + + template + struct LastIsInteger { + static constexpr bool value = LastIsInteger::value; + }; + + template + struct LastIsInteger { + static constexpr bool value + = std::is_integral::value && !std::is_same::value; + }; + + template + struct LastIsInteger T::*> { + static constexpr bool value + = std::is_integral::value && !std::is_same::value; + }; + + template + struct LastIsFloat { + static constexpr bool value = LastIsFloat::value; + }; + + template + struct LastIsFloat { + static constexpr bool value = std::is_same::value; + }; + + template + struct LastIsFloat T::*> { + static constexpr bool value = std::is_same::value; + }; + + template + struct LastIsVector { + using value_type = typename LastIsVector::value_type; + static constexpr bool value = LastIsVector::value; + }; + + template + struct LastIsVector T::*> { + using value_type = U; + static constexpr bool value = true; + }; + + template + struct LastIsVector { + using value_type = void; + static constexpr bool value = false; + }; + + template + static bool is_field_set(const nonstd::optional& field) + { + return field.has_value(); + } + + template + static bool is_field_set(const T&) + { + return true; + } + + template::value, bool> = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(bool_field_cb); + this->jph_bool_cb = [args...](yajlpp_parse_context* ypc, int val) { + auto* obj = ypc->ypc_obj_stack.top(); + + json_path_handler::get_field(obj, args...) = static_cast(val); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + + return *this; + } + + template< + typename... Args, + std::enable_if_t, 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 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; + + jph->validate_string(*ypc, value_str); + json_path_handler::get_field(obj, args...) + .emplace_back(std::move(value_str)); + + return 1; + }; + return *this; + } + + template::value, bool> = true, + std::enable_if_t< + !std::is_same::value_type, + std::string>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->jph_obj_provider + = [args...](const yajlpp_provider_context& ypc, void* root) { + auto& vec = json_path_handler::get_field(root, args...); + + if (ypc.ypc_index >= vec.size()) { + vec.resize(ypc.ypc_index + 1); + } + + return &vec[ypc.ypc_index]; + }; + this->jph_size_provider = [args...](void* root) { + auto& vec = json_path_handler::get_field(root, args...); + + return vec.size(); + }; + + return *this; + } + + template + json_path_handler& for_child(positioned_property(T::*field)) + { + this->jph_obj_provider + = [field](const yajlpp_provider_context& ypc, void* root) -> void* { + auto& child = json_path_handler::get_field(root, field); + + if (ypc.ypc_parse_context != nullptr && child.pp_path.empty()) { + child.pp_path = ypc.ypc_parse_context->get_full_path(); + } + return &child.pp_value; + }; + + return *this; + } + + template + json_path_handler& for_child(Args... args) + { + this->jph_obj_provider = [args...](const yajlpp_provider_context& ypc, + void* root) -> void* { + auto& child = json_path_handler::get_field(root, args...); + + return &child; + }; + + return *this; + } + + template, 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 unsigned char* str, + size_t len) { + 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); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + { + yajlpp_generator gen(handle); + + for (const auto& pair : field) { + gen(pair.first); + gen(pair.second); + } + } + + return yajl_gen_status_ok; + }; + return *this; + } + + template>, + 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 unsigned char* str, + size_t len) { + 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); + + return 1; + }; + this->add_cb(null_field_cb); + this->jph_null_cb = [args...](yajlpp_parse_context* ypc) { + auto* obj = ypc->ypc_obj_stack.top(); + auto key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] = nonstd::nullopt; + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + { + yajlpp_generator gen(handle); + + for (const auto& pair : field) { + gen(pair.first); + gen(pair.second); + } + } + + return yajl_gen_status_ok; + }; + return *this; + } + + template, Args...>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(bool_field_cb); + this->jph_bool_cb = [args...](yajlpp_parse_context* ypc, int val) { + auto* obj = ypc->ypc_obj_stack.top(); + auto key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] = val ? true + : false; + + return 1; + }; + this->add_cb(int_field_cb); + this->jph_integer_cb + = [args...](yajlpp_parse_context* ypc, long long val) { + auto* obj = ypc->ypc_obj_stack.top(); + auto key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] + = static_cast(val); + + return 1; + }; + 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 key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] + = std::string((const char*) str, len); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + { + yajlpp_generator gen(handle); + + for (const auto& pair : field) { + gen(pair.first); + pair.second.match([&gen](json_null_t v) { gen(); }, + [&gen](bool v) { gen(v); }, + [&gen](int64_t v) { gen(v); }, + [&gen](double v) { gen(v); }, + [&gen](const std::string& v) { gen(v); }); + } + } + + return yajl_gen_status_ok; + }; + return *this; + } + + template::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 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; + + jph->validate_string(*ypc, value_str); + json_path_handler::get_field(obj, args...) = std::move(value_str); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + return *this; + } + + template::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 unsigned char* str, + size_t len) { + auto obj = ypc->ypc_obj_stack.top(); + 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))); + } else { + json_path_handler::get_field(obj, args...) = tv; + } + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + char buf[64]; + + auto buf_len = lnav::strftime_rfc3339( + buf, sizeof(buf), field.tv_sec, field.tv_usec, 'T'); + + return gen(string_fragment::from_bytes(buf, buf_len)); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + return *this; + } + + template< + typename... Args, + std::enable_if_t, 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 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; + + jph->validate_string(*ypc, value_str); + json_path_handler::get_field(obj, args...) = std::move(value_str); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (!field) { + return yajl_gen_status_ok; + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field.value()); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + return *this; + } + + template, 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 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; + + jph->validate_string(*ypc, value_str); + 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 = std::move(value_str); + + 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); + }; + return *this; + } + + template::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 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; + + jph->validate_string(*ypc, value_str); + json_path_handler::get_field(obj, args...) + = intern_string::lookup(value_str); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field); + }; + return *this; + } + + template, 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 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; + + jph->validate_string(*ypc, value_str); + 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 = intern_string::lookup(value_str); + + 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); + }; + return *this; + } + + template + struct int_ { + typedef int type; + }; + template< + typename C, + typename T, + typename int_::type + = 0, + typename... Args> + 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) { + 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()}; + + auto from_res = T::from(ypc->get_full_path(), loc, value_frag); + if (from_res.isErr()) { + jph->report_error( + ypc, value_frag.to_string(), from_res.unwrapErr()); + } else { + json_path_handler::get_field(obj, args..., ptr_arg) + = from_res.unwrap(); + } + + return 1; + }; + return *this; + } + + template::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) { + 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...) = val; + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (!is_field_set(field)) { + return yajl_gen_status_ok; + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + + return *this; + } + + template::value, bool> = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(dbl_field_cb); + this->jph_double_cb = [args...](yajlpp_parse_context* ypc, double val) { + 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...) = val; + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (!is_field_set(field)) { + return yajl_gen_status_ok; + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(field); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + + return *this; + } + + template< + typename... Args, + std::enable_if_t::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 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)); + + 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); + return 1; + } + + json_path_handler::get_field(obj, args...) = std::chrono::seconds( + parse_res.template unwrap().to_timeval().tv_sec); + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(relative_time::from_timeval( + {static_cast(field.count()), 0}) + .to_string()); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + return *this; + } + + template::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 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)); + + if (res) { + json_path_handler::get_field(obj, args...) + = (typename LastIsEnum::value_type) res.value(); + } else { + handler->report_enum_error(ypc, + std::string((const char*) str, len)); + } + + 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 == field_def) { + return yajl_gen_status_ok; + } + } + + if (!is_field_set(field)) { + return yajl_gen_status_ok; + } + + if (ygc.ygc_depth) { + yajl_gen_string(handle, jph.jph_property); + } + + yajlpp_generator gen(handle); + + return gen(jph.to_enum_string(field)); + }; + this->jph_field_getter + = [args...](void* root, nonstd::optional name) { + return (void*) &json_path_handler::get_field(root, args...); + }; + + return *this; + } + + json_path_handler& with_children(const json_path_container& container); + + json_path_handler& with_example(const std::string& example) + { + this->jph_examples.emplace_back(example); + return *this; + } +}; + +struct json_path_container { + json_path_container(std::initializer_list children) + : jpc_children(children) + { + } + + json_path_container& with_definition_id(const std::string& id) + { + this->jpc_definition_id = id; + return *this; + } + + json_path_container& with_schema_id(const std::string& id) + { + this->jpc_schema_id = id; + return *this; + } + + json_path_container& with_description(std::string desc) + { + this->jpc_description = std::move(desc); + return *this; + } + + void gen_schema(yajlpp_gen_context& ygc) const; + + void gen_properties(yajlpp_gen_context& ygc) const; + + std::string jpc_schema_id; + std::string jpc_definition_id; + std::string jpc_description; + std::vector jpc_children; +}; + +template +class yajlpp_parser { +public: + yajlpp_parser(intern_string_t src, const json_path_container* container) + : yp_parse_context(src, container) + { + this->yp_handle = yajl_alloc(&this->yp_parse_context.ypc_callbacks, + nullptr, + &this->yp_parse_context); + this->yp_parse_context.with_handle(this->yp_handle); + this->yp_parse_context.template with_obj(this->yp_obj); + this->yp_parse_context.ypc_userdata = this; + this->yp_parse_context.with_error_reporter( + [](const auto& ypc, const auto& um) { + auto* yp = static_cast*>(ypc.ypc_userdata); + + yp->yp_errors.template emplace_back(um); + }); + } + + yajlpp_parser& with_ignore_unused(bool value) + { + this->yp_parse_context.with_ignore_unused(value); + + return *this; + } + + Result> of( + const string_fragment& json) + { + if (this->yp_parse_context.parse_doc(json)) { + return Ok(std::move(this->yp_obj)); + } + + return Err(std::move(this->yp_errors)); + } + +private: + yajlpp_parse_context yp_parse_context; + auto_mem yp_handle{yajl_free}; + std::vector yp_errors; + T yp_obj; +}; + +template +struct typed_json_path_container : public json_path_container { + typed_json_path_container(std::initializer_list children) + : json_path_container(children) + { + } + + typed_json_path_container& with_schema_id2(const std::string& id) + { + this->jpc_schema_id = id; + return *this; + } + + typed_json_path_container& with_description2(std::string desc) + { + this->jpc_description = std::move(desc); + return *this; + } + + yajlpp_parser parser_for(intern_string_t src) const + { + return yajlpp_parser{src, this}; + } + + std::string to_string(const T& obj) const + { + yajlpp_gen gen; + yajlpp_gen_context ygc(gen, *this); + ygc.template with_obj(obj); + ygc.ygc_depth = 1; + ygc.gen(); + + return gen.to_string_fragment().to_string(); + } + + json_string to_json_string(const T& obj) const + { + yajlpp_gen gen; + yajlpp_gen_context ygc(gen, *this); + ygc.template with_obj(obj); + ygc.ygc_depth = 1; + ygc.gen(); + + return json_string{gen.get_handle()}; + } +}; + +namespace yajlpp { +inline json_path_handler +property_handler(const std::string& path) +{ + return {path}; +} + +template +inline json_path_handler +pattern_property_handler(const T (&path)[N]) +{ + return {lnav::pcre2pp::code::from_const(path).to_shared()}; +} + +} // namespace yajlpp + +#endif -- cgit v1.2.3