Skip to content

Commit b088956

Browse files
committed
switch to a better library
1 parent 5737a9b commit b088956

File tree

3 files changed

+78
-41
lines changed

3 files changed

+78
-41
lines changed

CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ add_library(rlib STATIC
3838
lib/rlib/rmanifest.hpp
3939
)
4040
target_include_directories(rlib PUBLIC lib/)
41-
target_link_libraries(rlib PUBLIC argparse libcurl zstd digestpp fmt json miniz)
41+
target_link_libraries(rlib PUBLIC argparse libcurl zstd fmt)
42+
target_link_libraries(rlib PRIVATE json_struct digestpp miniz)
4243

4344
add_executable(rman-dl src/rman_dl.cpp)
4445
target_link_libraries(rman-dl PRIVATE rlib)

dep/CMakeLists.txt

+8-7
Original file line numberDiff line numberDiff line change
@@ -100,23 +100,24 @@ FetchContent_Declare(
100100
FetchContent_MakeAvailable(fmt)
101101

102102
FetchContent_Declare(
103-
json
104-
URL https://github.com/nlohmann/json/releases/download/v3.9.1/include.zip
103+
json_struct
104+
URL https://github.com/jorgen/json_struct/archive/de80d452b3cc1688dfc2967dbfef5cb501e925d3.zip
105105
CONFIGURE_COMMAND ""
106106
BUILD_COMMAND ""
107107
)
108-
FetchContent_GetProperties(json)
109-
if(NOT json_POPULATED)
110-
FetchContent_Populate(json)
111-
add_library(json INTERFACE)
112-
target_include_directories(json INTERFACE ${json_SOURCE_DIR}/include)
108+
FetchContent_GetProperties(json_struct)
109+
if(NOT json_struct_POPULATED)
110+
FetchContent_Populate(json_struct)
111+
add_library(json_struct INTERFACE)
112+
target_include_directories(json_struct INTERFACE ${json_struct_SOURCE_DIR}/include)
113113
endif()
114114

115115
FetchContent_Declare(
116116
miniz
117117
GIT_REPOSITORY https://github.com/richgel999/miniz.git
118118
GIT_TAG 76b3a872855388c735c564905da030f26334f3b3
119119
)
120+
120121
FetchContent_GetProperties(miniz)
121122
if(NOT miniz_POPULATED)
122123
FetchContent_Populate(miniz)

lib/rlib/rmanifest.cpp

+68-33
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#include "rmanifest.hpp"
22

3+
#include <json_struct/json_struct.h>
34
#include <zstd.h>
45

6+
#include <charconv>
57
#include <cstring>
68
#include <limits>
7-
#include <nlohmann/json.hpp>
89
#include <regex>
910
#include <stdexcept>
1011
#include <type_traits>
@@ -15,7 +16,63 @@
1516
#include "iofile.hpp"
1617

1718
using namespace rlib;
18-
using json = nlohmann::json;
19+
20+
namespace JS {
21+
template <typename T>
22+
struct TypeHandlerHex {
23+
static inline Error to(T& to_type, ParseContext& context) {
24+
auto const beg = context.token.value.data;
25+
auto const end = beg + context.token.value.size;
26+
auto value = std::uint64_t{};
27+
auto const ec_ptr = std::from_chars(beg, end, value, 16);
28+
if (ec_ptr.ec != std::errc{}) [[unlikely]] {
29+
return Error::FailedToParseInt;
30+
}
31+
to_type = static_cast<T>(value);
32+
return Error::NoError;
33+
}
34+
35+
static void from(T const& from_type, Token& token, Serializer& serializer) {
36+
std::string buf = fmt::format("{}", from_type);
37+
token.value_type = Type::String;
38+
token.value.data = buf.data();
39+
token.value.size = buf.size();
40+
serializer.write(token);
41+
}
42+
};
43+
44+
template <typename T, auto MINIMUM, auto MAXIMUM, typename U = std::underlying_type_t<T>>
45+
struct TypeHandlerEnum {
46+
static inline Error to(T& to_type, ParseContext& context) {
47+
auto tmp = U{};
48+
auto error = TypeHandler<U>::to(tmp, context);
49+
if (error == Error::NoError) {
50+
if (!(tmp >= MINIMUM && tmp <= MAXIMUM)) [[unlikely]] {
51+
error = Error::IllegalDataValue;
52+
} else {
53+
to_type = static_cast<T>(tmp);
54+
}
55+
}
56+
return error;
57+
}
58+
59+
static void from(T const& from_type, Token& token, Serializer& serializer) {
60+
TypeHandler<U>::from(static_cast<U>(from_type), token, serializer);
61+
}
62+
};
63+
64+
template <>
65+
struct TypeHandler<HashType> : TypeHandlerEnum<HashType, 0, 3> {};
66+
67+
template <>
68+
struct TypeHandler<FileID> : TypeHandlerHex<FileID> {};
69+
70+
template <>
71+
struct TypeHandler<ChunkID> : TypeHandlerHex<ChunkID> {};
72+
}
73+
74+
JS_OBJ_EXT(rlib::RChunk::Dst, chunkId, hash_type, uncompressed_size);
75+
JS_OBJ_EXT(rlib::RMAN::File, chunks, fileId, langs, link, path, permissions, size);
1976

2077
auto RMAN::Filter::operator()(File const& file) const noexcept -> bool {
2178
if (langs && !std::regex_search(file.langs, *langs)) {
@@ -447,46 +504,24 @@ auto RMAN::lookup() const -> std::unordered_map<std::string, File const*> {
447504
}
448505

449506
auto RMAN::File::dump() const -> std::string {
450-
auto const& file = *this;
451-
auto jfile = json{
452-
{"permissions", file.permissions},
453-
{"fileId", fmt::format("{}", file.fileId)},
454-
{"path", file.path},
455-
{"link", file.link},
456-
{"langs", file.langs},
457-
{"size", file.size},
458-
{"chunks", json::array()},
459-
};
460-
for (auto const& chunk : file.chunks) {
461-
jfile["chunks"].emplace_back() = json{
462-
{"chunkId", fmt::format("{}", chunk.chunkId)},
463-
{"uncompressed_size", chunk.uncompressed_size},
464-
{"hash_type", chunk.hash_type},
465-
};
466-
}
467-
auto result = jfile.dump();
507+
auto result = JS::serializeStruct(*this, JS::SerializerOptions(JS::SerializerOptions::Compact));
468508
result.push_back('\n');
469509
return result;
470510
}
471511

472512
auto RMAN::File::undump(std::string_view data) -> File {
513+
auto context = JS::ParseContext(data.data(), data.size());
473514
auto file = File{};
474-
auto jfile = json::parse(data);
475-
file.permissions = jfile.at("permissions");
476-
file.fileId = (FileID)from_hex(jfile.at("fileId")).value();
477-
file.path = jfile.at("path");
478-
file.link = jfile.at("link");
479-
file.langs = jfile.at("langs");
480-
file.size = jfile.at("size");
481-
for (std::uint64_t uncompressed_offset = 0; auto const& jchunk : jfile.at("chunks")) {
482-
auto& chunk = file.chunks.emplace_back();
483-
chunk.chunkId = (ChunkID)from_hex(jchunk.at("chunkId")).value();
484-
chunk.uncompressed_size = jchunk.at("uncompressed_size");
485-
chunk.hash_type = jchunk.at("hash_type");
515+
auto error = context.parseTo(file);
516+
if (error != JS::Error::NoError) {
517+
rlib_error(context.makeErrorString().c_str());
518+
}
519+
auto uncompressed_offset = std::uint64_t{};
520+
for (auto& chunk : file.chunks) {
486521
chunk.uncompressed_offset = uncompressed_offset;
487522
uncompressed_offset += chunk.uncompressed_size;
488-
rlib_assert((unsigned)chunk.hash_type > 0 && (unsigned)chunk.hash_type <= 3);
489523
}
524+
rlib_assert(uncompressed_offset == file.size);
490525
return file;
491526
}
492527

0 commit comments

Comments
 (0)