Skip to content

Commit

Permalink
-
Browse files Browse the repository at this point in the history
  • Loading branch information
Андрей Будиловский committed Feb 10, 2025
1 parent dd9cca1 commit d77d86a
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 24 deletions.
4 changes: 2 additions & 2 deletions benchmarks/fuzzing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ struct Storage {
file.exceptions(std::fstream::failbit | std::fstream::badbit);
file.open(path);
if (!file.is_open()) {
throw std::runtime_error("FUCK THIS SHIT");
throw std::runtime_error(fmt::format("can't open file on path : {}", path.generic_string()));
}
file << *json;
file.flush();
Expand Down Expand Up @@ -243,7 +243,7 @@ struct Storage {
file.exceptions(std::fstream::failbit | std::fstream::badbit);
file.open(path);
if (!file.is_open()) {
throw std::runtime_error("FUCK THIS SHIT");
throw std::runtime_error(fmt::format("can't open file on path : {}", path.generic_string()));
}
file << *json;
file.flush();
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/rapid_parse_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ T parse_handler(std::string_view sv) {
details::rapid_sv_stream ss(sv);
rapidjson::ParseResult parse_result = reader.Parse(ss, handler);
if (parse_result.IsError()) {
throw std::runtime_error(fmt::format("Fail parse"));
throw_json_parse_error();
}
return result;
}
Expand Down
1 change: 0 additions & 1 deletion cmake/deps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ CPMAddPackage(
OPTIONS "BOOST_ENABLE_CMAKE ON"
)
unset(BOOST_INCLUDE_LIBRARIES)
find_package(Boost 1.87 COMPONENTS system asio pfr json boost_container REQUIRED)

CPMAddPackage("gh:fmtlib/fmt#11.0.2")

Expand Down
94 changes: 94 additions & 0 deletions gtest/parsers/test_oneof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,98 @@ JSON_PARSE_TEST(OneOfHiddenUserTypeMoreData, MessageOrigin) {
EXPECT_EQ(parsed, expected);
}

TEST(GeneratorBoost, MissplaceDiscriminator) {
MessageOrigin expected{
.data =
MessageOriginChannel{
.date = tgbm::api::Integer{1630454400},
.sender_channel =
tgbm::box<Channel>{
Channel{
.id = tgbm::api::Integer{13579},
.name = "News Channel",
},
},
},
};

auto json = R"(
{
"date": 1630454400,
"sender_channel": {
"id": 13579,
"name": "News Channel"
},
"type": "channel"
}
)";

MessageOrigin parsed = GeneratorBoost::parse_json<MessageOrigin>(json);
EXPECT_EQ(parsed, expected);
}

TEST(GeneratorBoost, ArrayMissplaceDiscriminator) {
std::vector<MessageOrigin> expected{
MessageOrigin{
.data =
MessageOriginChannel{
.date = tgbm::api::Integer{1630454400},
.sender_channel =
tgbm::box<Channel>{
Channel{
.id = tgbm::api::Integer{13579},
.name = "News Channel",
},
},
},
},
MessageOrigin{
.data =
MessageOriginChat{
.date = tgbm::api::Integer{1630454400},
.sender_chat =
tgbm::box<Chat>{
Chat{
.id = tgbm::api::Integer{67890},
.title = "Group Chat",
},
},
},
},
};

auto json = R"(
[
{
"date":1630454400,
"type":"channel",
"sender_channel":{
"id":13579,
"name":"News Channel"
}
},
{
"date":1630454400,
"sender_chat":{
"id":67890,
"title":"Group Chat"
},
"type":"chat"
}
])";

auto parsed = GeneratorBoost::parse_json<std::vector<MessageOrigin>>(json);
EXPECT_EQ(parsed, expected);
}

JSON_PARSE_TEST(MissingField, MessageOrigin) {
MessageOrigin expected;
auto json = R"(
{
"date": 1630454400
}
)";
EXPECT_THROW(parse_json(json), tgbm::json::parse_error);
}

} // namespace test_oneof
3 changes: 2 additions & 1 deletion include/tgbm/jsons/boostjson_dom_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <boost/json.hpp>

#include <tgbm/jsons/dom_traits.hpp>
#include <tgbm/jsons/errors.hpp>
#include <tgbm/utils/macro.hpp>

namespace tgbm::json {
Expand Down Expand Up @@ -64,7 +65,7 @@ struct dom_traits_for<::boost::json::value> {
}

static void on_error() {
throw std::runtime_error("JSON Error");
throw_json_parse_error();
}

static const type* find_field(const type& json, std::string_view key) {
Expand Down
1 change: 1 addition & 0 deletions include/tgbm/jsons/parse_sax/common_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <tgbm/jsons/sax.hpp>
#include <tgbm/utils/pfr_extension.hpp>
#include <tgbm/utils/traits.hpp>
#include <tgbm/logger.hpp>

namespace tgbm::json {

Expand Down
45 changes: 41 additions & 4 deletions include/tgbm/jsons/parse_sax/discriminated_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,57 @@ struct sax_parser<T> {
return v.discriminate(key, emplacer);
}

static sax_consumer_t parse(T& v, sax_token& tok, dd::with_stack_resource r) {
static sax_consumer_t bufferized_parse(T& out, sax_token& tok, dd::with_stack_resource r) {
using enum sax_token::kind_e;

assert(tok.got != key || tok.str_m != T::discriminator);

std::vector<sax_token_value> buf_toks;
buf_toks.reserve(10);
{
sax_token token;
token.got = object_begin;
buf_toks.emplace_back(token);
}

do {
buf_toks.emplace_back(tok);
co_yield {};
} while (tok.got != key || tok.str_m != T::discriminator);

co_yield {};
tok.expect(string);

auto gen_suboneof = get_generator_suboneof(tok.str_m, out, tok, r);
auto it = gen_suboneof.cur_iterator();
for (auto& buf_tok : buf_toks) {
assert(it != gen_suboneof.end());
tok = buf_tok.to_view();
++it;
}

if (it != gen_suboneof.end()) {
co_yield {};
co_yield dd::elements_of(gen_suboneof);
}
}

static sax_consumer_t parse(T& out, sax_token& tok, dd::with_stack_resource r) {
using enum sax_token::kind_e;
tok.expect(object_begin);
co_yield {};
if (tok.got == object_end)
co_return;
tok.expect(key);
if (tok.got != key || tok.str_m != T::discriminator) [[unlikely]]
json::throw_json_parse_error();
if (tok.got != key || tok.str_m != T::discriminator) [[unlikely]] {
co_yield dd::elements_of(bufferized_parse(out, tok, r));
co_return;
}
co_yield {};
tok.expect(string);
// change 'got' before generator creation (may be function returning generator)
tok.got = object_begin;
co_yield dd::elements_of(get_generator_suboneof(tok.str_m, v, tok, r));
co_yield dd::elements_of(get_generator_suboneof(tok.str_m, out, tok, r));
}
};

Expand Down
3 changes: 2 additions & 1 deletion include/tgbm/jsons/rapidjson_dom_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <rapidjson/error/en.h>

#include <tgbm/jsons/dom_traits.hpp>
#include <tgbm/jsons/errors.hpp>

namespace tgbm::json {

Expand Down Expand Up @@ -75,7 +76,7 @@ struct dom_traits_for<rapidjson::GenericValue<rapidjson::UTF8<>>> {
}

static void on_error() {
throw std::runtime_error("JSON Error");
throw_json_parse_error();
}

static const type* find_field(const type& json, std::string_view key) {
Expand Down
Loading

0 comments on commit d77d86a

Please sign in to comment.