8000 Add built-in reflection for nlohmann and rapid json libraries. Resolv… · jinja2cpp/Jinja2Cpp@6d4a189 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6d4a189

Browse files
authored
Add built-in reflection for nlohmann and rapid json libraries. Resolves #78 (#130)
* Add reflection for nlohmann json library ( https://github.com/nlohmann/json ) * Add extra tests for nlohmann json reflectors * Implement reflection for RapidJson library ( https://github.com/Tencent/rapidjson ) * Fix build, add extra tests
1 parent 8d50ae8 commit 6d4a189

File tree

12 files changed

+770
-78
lines changed

12 files changed

+770
-78
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@
2323
[submodule "thirdparty/robin-hood-hashing"]
2424
path = thirdparty/robin-hood-hashing
2525
url = https://github.com/martinus/robin-hood-hashing.git
26+
[submodule "thirdparty/json/nlohmann"]
27+
path = thirdparty/json/nlohmann
28+
url = https://github.com/nlohmann/json.git
29+
[submodule "thirdparty/json/rapid"]
30+
path = thirdparty/json/rapid
31+
url = https://github.com/Tencent/rapidjson.git

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ target_include_directories(${LIB_TARGET_NAME}
149149

150150
if(JINJA2CPP_STRICT_WARNINGS)
151151
if(NOT MSVC)
152-
target_compile_options(${LIB_TARGET_NAME} PRIVATE -Wall -Werror)
152+
target_compile_options(${LIB_TARGET_NAME} PRIVATE -Wall -Werror -Wno-unused-command-line-argument)
153153
else ()
154154
target_compile_options(${LIB_TARGET_NAME} PRIVATE /W4)
155155
endif()
@@ -176,7 +176,8 @@ if (JINJA2CPP_BUILD_TESTS)
176176

177177
CollectSources(TestSources TestHeaders ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/test)
178178
add_executable(jinja2cpp_tests ${TestSources} ${TestHeaders})
179-
target_link_libraries(jinja2cpp_tests gtest gtest_main ${LIB_TARGET_NAME} ${EXTRA_TEST_LIBS})
179+
target_link_libraries(jinja2cpp_tests gtest gtest_main nlohmann_json ${LIB_TARGET_NAME} ${EXTRA_TEST_LIBS} )
180+
target_include_directories(jinja2cpp_tests PRIVATE ${RapidJSON_INCLUDE_DIR})
180181

181182
set_target_properties(jinja2cpp_tests PROPERTIES
182183
CXX_STANDARD ${JINJA2CPP_CXX_STANDARD}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Main features of Jinja2C++:
2222
- Easy-to-use public interface. Just load templates and render them.
2323
- Conformance to [Jinja2 specification](http://jinja.pocoo.org/docs/2.10/)
2424
- Full support of narrow- and wide-character strings both for templates and parameters.
25-
- Built-in reflection for C++ types.
25+
- Built-in reflection for the common C++ types, nlohmann and rapid JSON libraries.
2626
- Powerful full-featured Jinja2 expressions with filtering (via '|' operator) and 'if'-expressions.
2727
- Control statements (`set`, `for`, `if`, `do`, `with`).
2828
- Templates extention, including and importing
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#ifndef JINJA2CPP_BINDING_NLOHMANN_JSON_H
2+
#define JINJA2CPP_BINDING_NLOHMANN_JSON_H
3+
4+
#include <nlohmann/json.hpp>
5+
6+
#include <jinja2cpp/reflected_value.h>
7+
8+
namespace jinja2
9+
{
10+
namespace detail
11+
{
12+
13+
class NLohmannJsonObjectAccessor : public MapItemAccessor, public ReflectedDataHolder<nlohmann::json>
14+
{
15+
public:
16+
using ReflectedDataHolder<nlohmann::json>::ReflectedDataHolder;
17+
~NLohmannJsonObjectAccessor() override = default;
18+
19+
size_t GetSize() const override
20+
{
21+
auto j = this->GetValue();
22+
return j ? j->size() : 0ULL;
23+
}
24+
25+
bool HasValue(const std::string& name) const override
26+
{
27+
auto j = this->GetValue();
28+
return j ? j->contains(name) : false;
29+
}
30+
31+
Value GetValueByName(const std::string& name) const override
32+
{
33+
auto j = this->GetValue();
34+
if (!j || !j->contains(name))
35+
return Value();
36+
37+
return Reflect(&(*j)[name]);
38+
}
39+
40+
std::vector<std::string> GetKeys() const override
41+
{
42+
auto j = this->GetValue();
43+
if (!j)
44+
return {};
45+
46+
std::vector<std::string> result;
47+
for (auto& item : j->items())
48+
{
49+
result.emplace_back(item.key());
50+
}
51+
return result;
52+
}
53+
};
54+
55+
56+
struct NLohmannJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, ReflectedDataHolder<nlohmann::json>
57+
{
58+
using ReflectedDataHolder<nlohmann::json>::ReflectedDataHolder;
59+
60+
nonstd::optional<size_t> GetSize() const override
61+
{
62+
auto j = this->GetValue();
63+
return j ? j->size() : nonstd::optional<size_t>();
64+
}
65+
const IndexBasedAccessor* GetIndexer() const override
66+
{
67+
return this;
68+
}
69+
70+
ListEnumeratorPtr CreateEnumerator() const override
71+
{
72+
using Enum = Enumerator<typename nlohmann::json::const_iterator>;
73+
auto j = this->GetValue();
74+
if (!j)
75+
jinja2::ListEnumeratorPtr(nullptr, Enum::Deleter);
76+
77+
return jinja2::ListEnumeratorPtr(new Enum(j->begin(), j->end()), Enum::Deleter);
78+
}
79+
80+
Value GetItemByIndex(int64_t idx) const override
81+
{
82+
auto j = this->GetValue();
83+
if (!j)
84+
return Value();
85+
86+
return Reflect((*j)[idx]);
87+
}
88+
89+
size_t GetItemsCount() const override
90+
{
91+
auto sz = this->GetSize();
92+
return sz.value_or(0ULL);
93+
}
94+
};
95+
96+
template<>
97+
struct Reflector<nlohmann::json>
98+
{
99+
static Value Create(nlohmann::json val)
100+
{
101+
Value result;
102+
switch (val.type())
103+
{
104+
case nlohmann::detail::value_t::null:
105+
break;
106+
case nlohmann::detail::value_t::object:
107+
result = GenericMap([accessor = NLohmannJsonObjectAccessor(std::move(val))]() { return &accessor; });
108+
break;
109+
case nlohmann::detail::value_t::array:
110+
result = GenericList([accessor = NLohmannJsonArrayAccessor(std::move(val))]() { return &accessor; });
111+
break;
112+
case nlohmann::detail::value_t::string:
113+
result = val.get<std::string>();
114+
break;
115+
case nlohmann::detail::value_t::boolean:
116+
result = val.get<bool>();
117+
break;
118+
case nlohmann::detail::value_t::number_integer:
119+
case nlohmann::detail::value_t::number_unsigned:
120+
result = val.get<int64_t>();
121+
break;
122+
case nlohmann::detail::value_t::number_float:
123+
result = val.get<double>();
124+
break;
125+
case nlohmann::detail::value_t::discarded:
126+
break;
127+
}
128+
return result;
129+
}
130+
131+
static Value CreateFromPtr(const nlohmann::json *val)
132+
{
133+
Value result;
134+
switch (val->type())
135+
{
136+
case nlohmann::detail::value_t::null:
137+
break;
138+
case nlohmann::detail::value_t::object:
139+
result = GenericMap([accessor = NLohmannJsonObjectAccessor(val)]() { return &accessor; });
140+
break;
141+
case nlohmann::detail::value_t::array:
142+
result = GenericList([accessor = NLohmannJsonArrayAccessor(val)]() {return &accessor;});
143+
break;
144+
case nlohmann::detail::value_t::string:
145+
result = val->get<std::string>();
146+
break;
147+
case nlohmann::detail::value_t::boolean:
148+
result = val->get<bool>();
149+
break;
150+
case nlohmann::detail::value_t::number_integer:
151+
case nlohmann::detail::value_t::number_unsigned:
152+
result = val->get<int64_t>();
153+
break;
154+
case nlohmann::detail::value_t::number_float:
155+
result = val->get<double>();
156+
break;
157+
case nlohmann::detail::value_t::discarded:
158+
break;
159+
}
160+
return result;
161+
}
162+
163+
};
164+
165+
} // namespace detail
166+
} // namespace jinja2
167+
168+
#endif // JINJA2CPP_BINDING_NLOHMANN_JSON_H
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#ifndef JINJA2CPP_BINDING_RAPID_JSON_H
2+
#define JINJA2CPP_BINDING_RAPID_JSON_H
3+
4+
#include <rapidjson/rapidjson.h>
5+
#include <rapidjson/document.h>
6+
7+
#include <jinja2cpp/reflected_value.h>
8+
9+
namespace jinja2
10+
{
11+
namespace detail
12+
{
13+
14+
template<typename T>
15+
class RapidJsonObjectAccessor : public MapItemAccessor, public ReflectedDataHolder<T, false>
16+
{
17+
public:
18+
using ReflectedDataHolder<T, false>::ReflectedDataHolder;
19+
~RapidJsonObjectAccessor() override = default;
20+
21+
size_t GetSize() const override
22+
{
23+
auto j = this->GetValue();
24+
return j ? j->MemberCount() : 0ULL;
25+
}
26+
27+
bool HasValue(const std::string& name) const override
28+
{
29+
auto j = this->GetValue();
30+
return j ? j->HasMember(name.c_str()) : false;
31+
}
32+
33+
Value GetValueByName(const std::string& name) const override
34+
{
35+
auto j = this->GetValue();
36+
if (!j || !j->HasMember(name.c_str()))
37+
return Value();
38+
39+
return Reflect(&(*j)[name.c_str()]);
40+
}
41+
42+
std::vector<std::string> GetKeys() const override
43+
{
44+
auto j = this->GetValue();
45+
if (!j)
46+
return {};
47+
48+
std::vector<std::string> result;
49+
// for (auto& item : j->())
50+
for (auto it = j->MemberBegin(); it != j->MemberEnd(); ++ it)
51+
{
52+
result.emplace_back(it->name.GetString());
53+
}
54+
return result;
55+
}
56+
};
57+
58+
59+
struct RapidJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, ReflectedDataHolder<rapidjson::Value, false>
60+
{
61+
using ReflectedDataHolder<rapidjson::Value, false>::ReflectedDataHolder;
62+
63+
nonstd::optional<size_t> GetSize() const override
64+
{
65+
auto j = this->GetValue();
66+
return j ? j->Size() : nonstd::optional<size_t>();
67+
}
68+
const IndexBasedAccessor* GetIndexer() const override
69+
{
70+
return this;
71+
}
72+
73+
ListEnumeratorPtr CreateEnumerator() const override
74+
{
75+
using Enum = Enumerator<rapidjson::Value::ConstValueIterator>;
76+
auto j = this->GetValue();
77+
if (!j)
78+
jinja2::ListEnumeratorPtr(nullptr, Enum::Deleter);
79+
80+
return jinja2::ListEnumeratorPtr(new Enum(j->Begin(), j->End()), Enum::Deleter);
81+
}
82+
83+
Value GetItemByIndex(int64_t idx) const override
84+
{
85+
auto j = this->GetValue();
86+
if (!j)
87+
return Value();
88+
89+
return Reflect((*j)[idx]);
90+
}
91+
92+
size_t GetItemsCount() const override
93+
{
94+
auto sz = this->GetSize();
95+
return sz.value_or(0ULL);
96+
}
97+
};
98+
99+
template<>
100+
struct Reflector<rapidjson::Value>
101+
{
102+
static Value CreateFromPtr(const rapidjson::Value *val)
103+
{
104+
Value result;
105+
switch (val->GetType())
106+
{
107+
case rapidjson::kNullType:
108+
break;
109+
case rapidjson::kFalseType:
110+
result = Value(false);
111+
break;
112+
case rapidjson::kTrueType:
113+
result = Value(true);
114+
break;
115+
case rapidjson::kObjectType:
116+
result = GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::Value>(val)]() { return &accessor; });
117+
break;
118+
case rapidjson::kArrayType:
119+
result = GenericList([accessor = RapidJsonArrayAccessor(val)]() { return &accessor; });
120+
break;
121+
case rapidjson::kStringType:
122+
result = std::string(val->GetString(), val->GetStringLength());
123+
break;
124+
case rapidjson::kNumberType:
125+
if (val->IsInt64() || val->IsUint64())
126+
result = val->GetInt64();
127+
else if (val->IsInt() || val->IsUint())
128+
result = val->GetInt();
129+
else
130+
result = val->GetDouble();
131+
break;
132+
}
133+
return result;
134+
}
135+
136+
};
137+
138+
template<>
139+
struct Reflector<rapidjson::Document>
140+
{
141+
static Value Create(const rapidjson::Document& val)
142+
{
143+
return GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::Document>(&val)]() { return &accessor; });
144+
}
145+
146+
static Value CreateFromPtr(const rapidjson::Document *val)
147+
{
148+
return GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::Document>(val)]() { return &accessor; });
149+
}
150+
151+
};
152+
} // namespace detail
153+
} // namespace jinja2
154+
155+
#endif // JINJA2CPP_BINDING_RAPID_JSON_H

0 commit comments

Comments
 (0)
0