1#ifndef SIMDJSON_ANNOTATIONS_H
2#define SIMDJSON_ANNOTATIONS_H
38#if SIMDJSON_STATIC_REFLECTION
53 consteval fixed_string(
const char (&s)[N])
noexcept {
54 for (
size_t i = 0; i < N; ++i) { data[i] = s[i]; }
57 consteval std::string_view view() const noexcept {
return {data, N - 1}; }
59 consteval bool operator==(
const fixed_string&)
const noexcept =
default;
69enum class case_style {
81 template <fixed_
string Name>
83 static constexpr auto name = Name;
85 static constexpr const char *key_data = Name.data;
86 static constexpr size_t key_size = Name.view().size();
88 template <fixed_string... Names>
90 static_assert(
sizeof...(Names) > 0,
"simdjson::alias requires at least one name");
91 static constexpr std::string_view keys[] = {Names.view()...};
92 static constexpr const std::string_view *keys_data = keys;
93 static constexpr size_t keys_count =
sizeof...(Names);
96 struct skip_serializing_tag {};
97 struct skip_deserializing_tag {};
98 template <auto Predicate>
99 struct skip_serializing_if_t {
100 static constexpr auto predicate = Predicate;
102 struct default_value_tag {};
103 template <auto Factory>
104 struct default_from_t {
105 static constexpr auto factory = Factory;
107 template <
typename Adapter>
109 using adapter = Adapter;
111 template <case_style Style>
112 struct rename_all_t {
113 static constexpr case_style style = Style;
115 struct deny_unknown_fields_tag {};
116 struct transparent_tag {};
117 struct flatten_tag {};
121 template <
typename T>
122 constexpr bool operator()(
const T& v)
const noexcept {
return !v; }
125 template <
typename T>
126 constexpr bool operator()(
const T& v)
const noexcept {
return v.empty(); }
131template <fixed_
string Name>
132inline constexpr detail::rename_t<Name> rename{};
138template <fixed_string... Names>
139inline constexpr detail::alias_t<Names...> alias{};
142inline constexpr detail::skip_tag skip{};
145inline constexpr detail::skip_serializing_tag skip_serializing{};
150inline constexpr detail::skip_deserializing_tag skip_deserializing{};
155template <auto Predicate>
156inline constexpr detail::skip_serializing_if_t<Predicate> skip_serializing_if{};
159inline constexpr detail::is_none_t is_none{};
161inline constexpr detail::is_empty_t is_empty{};
167inline constexpr detail::default_value_tag default_value{};
173template <auto Factory>
174inline constexpr detail::default_from_t<Factory> default_from{};
182template <
typename Adapter>
183inline constexpr detail::with_t<Adapter> with{};
190inline constexpr detail::flatten_tag flatten{};
194template <case_style Style>
195inline constexpr detail::rename_all_t<Style> rename_all{};
200inline constexpr detail::deny_unknown_fields_tag deny_unknown_fields{};
205inline constexpr detail::transparent_tag transparent{};
211consteval bool has_annotation(std::meta::info entity, std::meta::info tag) {
212 return !std::meta::annotations_of_with_type(entity, tag).empty();
217consteval std::meta::info annotation_of_template(std::meta::info entity, std::meta::info tmpl) {
218 for (std::meta::info ann : std::meta::annotations_of(entity)) {
219 std::meta::info type = std::meta::type_of(ann);
220 if (std::meta::has_template_arguments(type) && std::meta::template_of(type) == tmpl) {
224 return std::meta::info{};
229consteval T static_member_value(std::meta::info type, std::string_view name) {
230 for (std::meta::info m : std::meta::static_data_members_of(type, std::meta::access_context::unchecked())) {
231 if (std::meta::has_identifier(m) && std::meta::identifier_of(m) == name) {
232 return std::meta::extract<T>(m);
238consteval bool is_upper(
char c) {
return c >=
'A' && c <=
'Z'; }
239consteval bool is_lower(
char c) {
return c >=
'a' && c <=
'z'; }
240consteval bool is_digit(
char c) {
return c >=
'0' && c <=
'9'; }
241consteval char to_upper(
char c) {
return is_lower(c) ? char(c -
'a' +
'A') : c; }
242consteval char to_lower(
char c) {
return is_upper(c) ? char(c -
'A' +
'a') : c; }
247consteval std::vector<std::string> split_identifier(std::string_view
id) {
248 std::vector<std::string> words;
250 for (
size_t i = 0; i <
id.size(); i++) {
253 if (!current.empty()) { words.push_back(current); current.clear(); }
256 if (is_upper(c) && !current.empty()) {
257 char prev = current.back();
258 bool next_is_lower = (i + 1 <
id.size()) && is_lower(
id[i + 1]);
259 if (is_lower(prev) || is_digit(prev) || (is_upper(prev) && next_is_lower)) {
260 words.push_back(current);
264 current.push_back(c);
266 if (!current.empty()) { words.push_back(current); }
270consteval std::string apply_case_style(std::string_view
id, case_style style) {
272 if (style == case_style::lowercase || style == case_style::uppercase) {
274 result.push_back(style == case_style::lowercase ? to_lower(c) : to_upper(c));
278 std::vector<std::string> words = split_identifier(
id);
279 for (
size_t w = 0; w < words.size(); w++) {
280 const std::string &word = words[w];
281 if (style == case_style::pascal_case || style == case_style::camel_case) {
282 for (
size_t i = 0; i < word.size(); i++) {
283 bool capital = (i == 0) && (style == case_style::pascal_case || w > 0);
284 result.push_back(capital ? to_upper(word[i]) : to_lower(word[i]));
287 bool upper = style == case_style::screaming_snake_case || style == case_style::screaming_kebab_case;
288 bool kebab = style == case_style::kebab_case || style == case_style::screaming_kebab_case;
289 if (w > 0) { result.push_back(kebab ?
'-' :
'_'); }
290 for (
char c : word) { result.push_back(upper ? to_upper(c) : to_lower(c)); }
299consteval std::string_view json_key_name(std::meta::info entity) {
300 std::meta::info rename_type = annotation_of_template(entity, ^^rename_t);
301 if (rename_type != std::meta::info{}) {
302 return std::define_static_string(std::string_view{
303 static_member_value<const char *>(rename_type,
"key_data"),
304 static_member_value<size_t>(rename_type,
"key_size")});
306 std::meta::info rename_all_type = annotation_of_template(std::meta::parent_of(entity), ^^rename_all_t);
307 if (rename_all_type != std::meta::info{}) {
308 case_style style = static_member_value<case_style>(rename_all_type,
"style");
309 return std::define_static_string(apply_case_style(std::meta::identifier_of(entity), style));
311 return std::define_static_string(std::meta::identifier_of(entity));
316consteval std::vector<std::string_view> json_key_names(std::meta::info entity) {
317 std::vector<std::string_view> names{json_key_name(entity)};
318 for (std::meta::info ann : std::meta::annotations_of(entity)) {
319 std::meta::info type = std::meta::type_of(ann);
320 if (std::meta::has_template_arguments(type) && std::meta::template_of(type) == ^^alias_t) {
321 const std::string_view *keys = static_member_value<const std::string_view *>(type,
"keys_data");
322 size_t count = static_member_value<size_t>(type,
"keys_count");
323 for (
size_t i = 0; i < count; i++) { names.push_back(keys[i]); }
330consteval std::meta::info flattened_type(std::meta::info mem) {
331 if (std::meta::is_reference_type(std::meta::type_of(mem))) {
334 throw std::meta::exception(u8
"simdjson::flatten requires a member that is not a reference", mem);
336 std::meta::info type = std::meta::remove_cvref(std::meta::type_of(mem));
337 if (!std::meta::is_class_type(type)) {
338 throw std::meta::exception(u8
"simdjson::flatten requires a member of class type", mem);
345consteval std::meta::info transparent_member(std::meta::info type) {
346 std::vector<std::meta::info> members;
347 for (std::meta::info mem : std::meta::nonstatic_data_members_of(type, std::meta::access_context::unchecked())) {
348 if (!has_annotation(mem, ^^skip_tag)) { members.push_back(mem); }
350 if (members.size() != 1) {
351 throw std::meta::exception(u8
"simdjson::transparent requires exactly one data member (not counting skipped members)", type);
360consteval const char* get_json_key_name() {
361 return detail::json_key_name(dm).data();
simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept
Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user i...
The top level simdjson namespace, containing everything the library provides.