skir-cc-gen 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -0
- package/client/BUILD.bazel +33 -0
- package/client/MODULE.bazel +11 -0
- package/client/MODULE.bazel.lock +225 -0
- package/client/skir.cc +2687 -0
- package/client/skir.h +2946 -0
- package/client/skir.testing.h +282 -0
- package/dist/enum_field.d.ts +33 -0
- package/dist/enum_field.d.ts.map +1 -0
- package/dist/enum_field.js +85 -0
- package/dist/enum_field.js.map +1 -0
- package/dist/enum_variant.d.ts +31 -0
- package/dist/enum_variant.d.ts.map +1 -0
- package/dist/enum_variant.js +85 -0
- package/dist/enum_variant.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1627 -0
- package/dist/index.js.map +1 -0
- package/dist/keywords.d.ts +2 -0
- package/dist/keywords.d.ts.map +1 -0
- package/dist/keywords.js +101 -0
- package/dist/keywords.js.map +1 -0
- package/dist/recursivity_resolver.d.ts +58 -0
- package/dist/recursivity_resolver.d.ts.map +1 -0
- package/dist/recursivity_resolver.js +142 -0
- package/dist/recursivity_resolver.js.map +1 -0
- package/dist/type_speller.d.ts +17 -0
- package/dist/type_speller.d.ts.map +1 -0
- package/dist/type_speller.js +87 -0
- package/dist/type_speller.js.map +1 -0
- package/package.json +55 -0
- package/src/enum_variant.ts +126 -0
- package/src/index.ts +2089 -0
- package/src/keywords.ts +100 -0
- package/src/recursivity_resolver.ts +161 -0
- package/src/type_speller.ts +100 -0
package/client/skir.h
ADDED
|
@@ -0,0 +1,2946 @@
|
|
|
1
|
+
// Skir client library
|
|
2
|
+
|
|
3
|
+
#ifndef SKIR_SKIR_H_VERSION
|
|
4
|
+
#define SKIR_SKIR_H_VERSION 20251220
|
|
5
|
+
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
#include <cmath>
|
|
8
|
+
#include <cstddef>
|
|
9
|
+
#include <cstdint>
|
|
10
|
+
#include <cstdlib>
|
|
11
|
+
#include <cstring>
|
|
12
|
+
#include <initializer_list>
|
|
13
|
+
#include <iostream>
|
|
14
|
+
#include <limits>
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <sstream>
|
|
17
|
+
#include <string>
|
|
18
|
+
#include <tuple>
|
|
19
|
+
#include <type_traits>
|
|
20
|
+
#include <utility>
|
|
21
|
+
#include <variant>
|
|
22
|
+
#include <vector>
|
|
23
|
+
|
|
24
|
+
#include "absl/base/nullability.h"
|
|
25
|
+
#include "absl/container/flat_hash_map.h"
|
|
26
|
+
#include "absl/hash/hash.h"
|
|
27
|
+
#include "absl/log/absl_check.h"
|
|
28
|
+
#include "absl/log/die_if_null.h"
|
|
29
|
+
#include "absl/status/status.h"
|
|
30
|
+
#include "absl/status/statusor.h"
|
|
31
|
+
#include "absl/strings/match.h"
|
|
32
|
+
#include "absl/strings/str_cat.h"
|
|
33
|
+
#include "absl/strings/str_join.h"
|
|
34
|
+
#include "absl/strings/str_replace.h"
|
|
35
|
+
#include "absl/strings/string_view.h"
|
|
36
|
+
#include "absl/time/time.h"
|
|
37
|
+
#include "absl/types/optional.h"
|
|
38
|
+
|
|
39
|
+
namespace skir_internal {
|
|
40
|
+
class ByteSink;
|
|
41
|
+
struct RecAdapter;
|
|
42
|
+
|
|
43
|
+
template <typename T, typename Getter>
|
|
44
|
+
using getter_value_type = std::remove_const_t<
|
|
45
|
+
std::remove_reference_t<decltype(Getter()(std::declval<T&>()))>>;
|
|
46
|
+
} // namespace skir_internal
|
|
47
|
+
|
|
48
|
+
namespace skir {
|
|
49
|
+
|
|
50
|
+
// What to do with unrecognized fields and variants when parsing a skir value
|
|
51
|
+
// from JSON or binary data.
|
|
52
|
+
// Pick kKeep if the input JSON or binary string comes from a trusted program
|
|
53
|
+
// which might have been built from more recent source files.
|
|
54
|
+
// Always pick kDrop if the input JSON or binary string might come from a
|
|
55
|
+
// malicious user.
|
|
56
|
+
//
|
|
57
|
+
// Default: kDrop
|
|
58
|
+
enum class UnrecognizedValuesPolicy { kDrop, kKeep };
|
|
59
|
+
|
|
60
|
+
// A string of bytes.
|
|
61
|
+
//
|
|
62
|
+
// Skir uses std::string exclusively for UTF-8 string, and ByteString for
|
|
63
|
+
// binary data.
|
|
64
|
+
class ByteString {
|
|
65
|
+
public:
|
|
66
|
+
ByteString() = default;
|
|
67
|
+
|
|
68
|
+
ByteString(absl::string_view str)
|
|
69
|
+
: data_(CopyData(str)), length_(str.length()) {}
|
|
70
|
+
|
|
71
|
+
ByteString(std::initializer_list<uint8_t> bytes)
|
|
72
|
+
: ByteString(
|
|
73
|
+
absl::string_view((const char*)bytes.begin(), bytes.size())) {}
|
|
74
|
+
|
|
75
|
+
ByteString(const ByteString& other) : ByteString(other.as_string()) {}
|
|
76
|
+
ByteString(ByteString&& other) : data_(other.data_), length_(other.length_) {
|
|
77
|
+
other.data_ = nullptr;
|
|
78
|
+
other.length_ = 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
~ByteString() { FreeData(); }
|
|
82
|
+
|
|
83
|
+
ByteString& operator=(absl::string_view other) {
|
|
84
|
+
FreeData();
|
|
85
|
+
data_ = CopyData(other);
|
|
86
|
+
length_ = other.length();
|
|
87
|
+
return *this;
|
|
88
|
+
}
|
|
89
|
+
ByteString& operator=(const ByteString& other) {
|
|
90
|
+
return (*this) = other.as_string();
|
|
91
|
+
}
|
|
92
|
+
ByteString& operator=(ByteString&& other) {
|
|
93
|
+
FreeData();
|
|
94
|
+
data_ = other.data_;
|
|
95
|
+
length_ = other.length_;
|
|
96
|
+
other.data_ = nullptr;
|
|
97
|
+
other.length_ = 0;
|
|
98
|
+
return *this;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
absl::string_view as_string() const& {
|
|
102
|
+
return absl::string_view((const char*)data_, length_);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
std::string as_string() const&& {
|
|
106
|
+
return std::string((const char*)data_, length_);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
size_t length() const { return length_; }
|
|
110
|
+
|
|
111
|
+
bool empty() const { return length_ == 0; }
|
|
112
|
+
|
|
113
|
+
bool operator==(const ByteString& other) const {
|
|
114
|
+
return as_string() == other.as_string();
|
|
115
|
+
}
|
|
116
|
+
bool operator!=(const ByteString& other) const {
|
|
117
|
+
return as_string() != other.as_string();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private:
|
|
121
|
+
static_assert(sizeof(char) == 1);
|
|
122
|
+
|
|
123
|
+
ByteString(const uint8_t* absl_nonnull data, size_t length)
|
|
124
|
+
: data_(data), length_(length) {}
|
|
125
|
+
|
|
126
|
+
const uint8_t* absl_nonnull data_ = nullptr;
|
|
127
|
+
size_t length_ = 0;
|
|
128
|
+
|
|
129
|
+
void FreeData() const {
|
|
130
|
+
if (data_ != nullptr) {
|
|
131
|
+
delete[] data_;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static uint8_t* absl_nullable CopyData(absl::string_view str) {
|
|
136
|
+
if (str.empty()) return nullptr;
|
|
137
|
+
uint8_t* result = new uint8_t[str.length()];
|
|
138
|
+
std::memcpy(result, (const uint8_t*)str.data(), str.length());
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
friend class ::skir_internal::ByteSink;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
template <typename H>
|
|
146
|
+
H AbslHashValue(H h, const ByteString& byte_string) {
|
|
147
|
+
return H::combine(std::move(h), byte_string.as_string());
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
template <typename T, typename GetKey>
|
|
151
|
+
using key_type =
|
|
152
|
+
std::conditional_t<std::is_same<skir_internal::getter_value_type<T, GetKey>,
|
|
153
|
+
std::string>::value,
|
|
154
|
+
absl::string_view,
|
|
155
|
+
skir_internal::getter_value_type<T, GetKey>>;
|
|
156
|
+
|
|
157
|
+
// A vector-like container that stores items of type T and allows for fast
|
|
158
|
+
// lookups by key using a hash table. The key is extracted from each item
|
|
159
|
+
// using a user-provided GetKey function.
|
|
160
|
+
//
|
|
161
|
+
// Example:
|
|
162
|
+
// keyed_items<User, skirout::get_id> users;
|
|
163
|
+
// users.push_back({.id = 1, .name = "Alice"});
|
|
164
|
+
// users.push_back({.id = 2, .name = "Bob"});
|
|
165
|
+
// const User* user = users.find_or_null(1); // returns pointer to Alice
|
|
166
|
+
//
|
|
167
|
+
// If multiple items in the container have the same key, only the last one can
|
|
168
|
+
// be found when calling find_or_null() or find_or_default().
|
|
169
|
+
//
|
|
170
|
+
// Accessors, such as at(), operator[], front(), and back() all return constant
|
|
171
|
+
// references. Once you have pushed a value into the container, the only way to
|
|
172
|
+
// modify the item is to use a vector_mutator, which is obtained by calling
|
|
173
|
+
// start_vector_mutation(). The vector_mutator lets you access the underlying
|
|
174
|
+
// std::vector<T> and modify it. While the vector mutation is in progress, you
|
|
175
|
+
// must not access the keyed_items. When the vector_mutator is destroyed, all
|
|
176
|
+
// the items in the vector are rehashed, which runs in O(N).
|
|
177
|
+
//
|
|
178
|
+
// Example:
|
|
179
|
+
// keyed_items<User, skirout::get_id> users;
|
|
180
|
+
// users.push_back({.id = 1, .name = "Alice"});
|
|
181
|
+
// users.push_back({.id = 2, .name = "Bob"});
|
|
182
|
+
//
|
|
183
|
+
// {
|
|
184
|
+
// auto mutator = users.start_vector_mutation();
|
|
185
|
+
// for (User& user : *mutator) {
|
|
186
|
+
// user.name = absl:::AsciiStrToLower(user.name);
|
|
187
|
+
// }
|
|
188
|
+
// }
|
|
189
|
+
//
|
|
190
|
+
// // Okay to access `users` here because the vector_mutator has been
|
|
191
|
+
// // destroyed.
|
|
192
|
+
//
|
|
193
|
+
// assert(users.find_or_default(1).name == "alice");
|
|
194
|
+
//
|
|
195
|
+
// The as_vector() method returns a constant reference to the underlying
|
|
196
|
+
// std::vector<T>.
|
|
197
|
+
template <typename T, typename GetKey>
|
|
198
|
+
class keyed_items {
|
|
199
|
+
public:
|
|
200
|
+
using value_type = T;
|
|
201
|
+
using get_key = GetKey;
|
|
202
|
+
using iterator = typename std::vector<T>::const_iterator;
|
|
203
|
+
using const_iterator = typename std::vector<T>::const_iterator;
|
|
204
|
+
using reverse_iterator = typename std::vector<T>::const_reverse_iterator;
|
|
205
|
+
using const_reverse_iterator =
|
|
206
|
+
typename std::vector<T>::const_reverse_iterator;
|
|
207
|
+
|
|
208
|
+
keyed_items() = default;
|
|
209
|
+
|
|
210
|
+
keyed_items(const keyed_items& other)
|
|
211
|
+
: vector_(other.vector_),
|
|
212
|
+
slots_bytes_(other.slots_bytes_),
|
|
213
|
+
slot_type_(other.slot_type_) {
|
|
214
|
+
ABSL_CHECK(!other.being_mutated_);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
keyed_items(keyed_items&& other)
|
|
218
|
+
: vector_(std::move(other.vector_)),
|
|
219
|
+
slots_bytes_(std::move(other.slots_bytes_)),
|
|
220
|
+
slot_type_(other.slot_type_) {
|
|
221
|
+
ABSL_CHECK(!other.being_mutated_);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
template <typename InputIt>
|
|
225
|
+
keyed_items(InputIt first, InputIt last) : vector_(first, last) {
|
|
226
|
+
Rehash();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
keyed_items(std::initializer_list<T> init) : vector_(std::move(init)) {
|
|
230
|
+
Rehash();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
keyed_items(std::vector<T> vector) : vector_(std::move(vector)) { Rehash(); }
|
|
234
|
+
|
|
235
|
+
~keyed_items() { ABSL_CHECK(!being_mutated_); }
|
|
236
|
+
|
|
237
|
+
keyed_items& operator=(const keyed_items& other) {
|
|
238
|
+
ABSL_CHECK(!being_mutated_);
|
|
239
|
+
ABSL_CHECK(!other.being_mutated_);
|
|
240
|
+
vector_ = other.vector_;
|
|
241
|
+
slots_bytes_ = other.slots_bytes_;
|
|
242
|
+
slot_type_ = other.slot_type_;
|
|
243
|
+
return *this;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
keyed_items& operator=(keyed_items&& other) {
|
|
247
|
+
ABSL_CHECK(!being_mutated_);
|
|
248
|
+
ABSL_CHECK(!other.being_mutated_);
|
|
249
|
+
vector_ = std::move(other.vector_);
|
|
250
|
+
slots_bytes_ = std::move(other.slots_bytes_);
|
|
251
|
+
slot_type_ = std::move(other.slot_type_);
|
|
252
|
+
return *this;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
keyed_items& operator=(std::vector<T> other) {
|
|
256
|
+
ABSL_CHECK(!being_mutated_);
|
|
257
|
+
vector_ = std::move(other);
|
|
258
|
+
Rehash();
|
|
259
|
+
return *this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
keyed_items& operator=(std::initializer_list<T> init) {
|
|
263
|
+
ABSL_CHECK(!being_mutated_);
|
|
264
|
+
vector_ = std::vector<T>(std::move(init));
|
|
265
|
+
Rehash();
|
|
266
|
+
return *this;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
template <typename InputIt>
|
|
270
|
+
void assign(InputIt first, InputIt last) {
|
|
271
|
+
ABSL_CHECK(!being_mutated_);
|
|
272
|
+
vector_ = std::vector<T>(first, last);
|
|
273
|
+
Rehash();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const T& at(size_t index) const { return vector().at(index); }
|
|
277
|
+
const T& operator[](size_t index) const { return vector()[index]; }
|
|
278
|
+
const T& front() const { return vector().front(); }
|
|
279
|
+
const T& back() const { return vector().back(); }
|
|
280
|
+
|
|
281
|
+
auto begin() const { return vector().begin(); }
|
|
282
|
+
auto cbegin() const { return begin(); }
|
|
283
|
+
auto end() const { return vector().end(); }
|
|
284
|
+
auto cend() const { return end(); }
|
|
285
|
+
|
|
286
|
+
auto rbegin() const { return vector().rbegin(); }
|
|
287
|
+
auto crbegin() const { return rbegin(); }
|
|
288
|
+
auto rend() const { return vector().rend(); }
|
|
289
|
+
auto crend() const { return rend(); }
|
|
290
|
+
|
|
291
|
+
bool empty() const { return vector_.empty(); }
|
|
292
|
+
size_t size() const { return vector_.size(); }
|
|
293
|
+
|
|
294
|
+
void reserve(size_t new_cap) {
|
|
295
|
+
ABSL_CHECK(!being_mutated_);
|
|
296
|
+
vector_.reserve(new_cap);
|
|
297
|
+
MaybeRehash();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
size_t capacity() const { return vector().capacity(); }
|
|
301
|
+
|
|
302
|
+
void shrink_to_fit() {
|
|
303
|
+
ABSL_CHECK(!being_mutated_);
|
|
304
|
+
vector_.shrink_to_fit();
|
|
305
|
+
MaybeRehash();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
void clear() {
|
|
309
|
+
ABSL_CHECK(!being_mutated_);
|
|
310
|
+
vector_.clear();
|
|
311
|
+
Rehash();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
void push_back(T value) {
|
|
315
|
+
ABSL_CHECK(!being_mutated_);
|
|
316
|
+
vector_.push_back(std::move(value));
|
|
317
|
+
if (MaybeRehash()) return;
|
|
318
|
+
const size_t next_index = vector_.size();
|
|
319
|
+
using key_type = key_type<T, GetKey>;
|
|
320
|
+
const uint32_t key_hash = absl::Hash<key_type>{}(GetKey()(vector_.back()));
|
|
321
|
+
PutSlot(key_hash, next_index, slot_type_);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
void append_range(const keyed_items<T, GetKey>& rg) { append_range_impl(rg); }
|
|
325
|
+
void append_range(keyed_items<T, GetKey>&& rg) {
|
|
326
|
+
append_range_impl(std::move(rg));
|
|
327
|
+
}
|
|
328
|
+
void append_range(const std::vector<T>& rg) { append_range_impl(rg); }
|
|
329
|
+
void append_range(std::vector<T>&& rg) { append_range_impl(std::move(rg)); }
|
|
330
|
+
|
|
331
|
+
void swap(keyed_items& other) noexcept {
|
|
332
|
+
ABSL_CHECK(!being_mutated_);
|
|
333
|
+
ABSL_CHECK(!other.being_mutated_);
|
|
334
|
+
vector_.swap(other.vector_);
|
|
335
|
+
slots_bytes_.swap(other.slots_bytes_);
|
|
336
|
+
std::swap(slot_type_, other.slot_type_);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Returns a pointer to the last item with the given key or nullptr if no such
|
|
340
|
+
// item exists.
|
|
341
|
+
template <typename K>
|
|
342
|
+
const T* absl_nullable find_or_null(const K& key) const {
|
|
343
|
+
return find_or_null_impl(key_type<T, GetKey>(key));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Returns the last item with the given key or a constant reference to a
|
|
347
|
+
// zero-initialized T if no such item exists.
|
|
348
|
+
//
|
|
349
|
+
// In some cases, this can help you write more succint code than if you were
|
|
350
|
+
// using find_or_null. For example, instead of:
|
|
351
|
+
//
|
|
352
|
+
// if (users.find_or_null(id) != nullptr &&
|
|
353
|
+
// !users.find_or_null(id)->name.empty()) { ... }
|
|
354
|
+
//
|
|
355
|
+
// you can write:
|
|
356
|
+
//
|
|
357
|
+
// if (!users.find_or_default(id).name.empty()) { ... }
|
|
358
|
+
template <typename K>
|
|
359
|
+
const T& find_or_default(const K& key) const {
|
|
360
|
+
return find_or_default_impl(key_type<T, GetKey>(key));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Returns the last item with the given key or default_value if no such item
|
|
364
|
+
// exists.
|
|
365
|
+
template <typename K>
|
|
366
|
+
const T& find_or_default(const K& key, const T& default_value) const {
|
|
367
|
+
return find_or_default_impl(key_type<T, GetKey>(key), default_value);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
void sort_by_key() {
|
|
371
|
+
ABSL_CHECK(!being_mutated_);
|
|
372
|
+
std::sort(vector_.begin(), vector_.end(),
|
|
373
|
+
[](const T& a, const T& b) { return GetKey()(a) < GetKey()(b); });
|
|
374
|
+
Rehash();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const std::vector<T>& vector() const& { return vector_; }
|
|
378
|
+
std::vector<T> vector() && { return std::move(vector_); }
|
|
379
|
+
|
|
380
|
+
bool operator==(const keyed_items& other) const {
|
|
381
|
+
return vector() == other.vector();
|
|
382
|
+
}
|
|
383
|
+
bool operator!=(const keyed_items& other) const {
|
|
384
|
+
return vector() != other.vector();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
class vector_mutator {
|
|
388
|
+
public:
|
|
389
|
+
vector_mutator(const vector_mutator&) = delete;
|
|
390
|
+
vector_mutator(vector_mutator&&) = delete;
|
|
391
|
+
vector_mutator& operator=(const vector_mutator&) = delete;
|
|
392
|
+
vector_mutator& operator=(vector_mutator&&) = delete;
|
|
393
|
+
|
|
394
|
+
~vector_mutator() {
|
|
395
|
+
keyed_items_.Rehash();
|
|
396
|
+
keyed_items_.being_mutated_ = false;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
std::vector<T>& operator*() & { return keyed_items_.vector_; }
|
|
400
|
+
std::vector<T>* absl_nonnull operator->() & {
|
|
401
|
+
return &keyed_items_.vector_;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
std::vector<T>& operator*() && = delete;
|
|
405
|
+
std::vector<T>* absl_nonnull operator->() && = delete;
|
|
406
|
+
|
|
407
|
+
private:
|
|
408
|
+
vector_mutator(keyed_items* absl_nonnull keyed_items)
|
|
409
|
+
: keyed_items_(*keyed_items) {}
|
|
410
|
+
|
|
411
|
+
keyed_items& keyed_items_;
|
|
412
|
+
|
|
413
|
+
friend class keyed_items;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// Starts a vector mutation which will stay active until the vector_mutator
|
|
417
|
+
// is destroyed. While the vector_mutator is active, you must not call any
|
|
418
|
+
// method on the keyed_items.
|
|
419
|
+
// See class-level documentation.
|
|
420
|
+
vector_mutator start_vector_mutation() & {
|
|
421
|
+
ABSL_CHECK(!being_mutated_);
|
|
422
|
+
being_mutated_ = true;
|
|
423
|
+
return vector_mutator(this);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
vector_mutator start_vector_mutation() && = delete;
|
|
427
|
+
|
|
428
|
+
private:
|
|
429
|
+
std::vector<T> vector_;
|
|
430
|
+
std::vector<uint8_t> slots_bytes_;
|
|
431
|
+
enum class SlotType {
|
|
432
|
+
kUint8,
|
|
433
|
+
kUint16,
|
|
434
|
+
kUint32,
|
|
435
|
+
kUint64,
|
|
436
|
+
};
|
|
437
|
+
SlotType slot_type_ = SlotType::kUint8;
|
|
438
|
+
bool being_mutated_ = false;
|
|
439
|
+
|
|
440
|
+
bool MaybeRehash() {
|
|
441
|
+
const size_t capacity = vector_.capacity();
|
|
442
|
+
const SlotType slot_type = GetSlotType(capacity);
|
|
443
|
+
const size_t num_slots_bytes = GetNumSlotsBytes(capacity, slot_type);
|
|
444
|
+
if (slot_type == slot_type_ && num_slots_bytes == slots_bytes_.size())
|
|
445
|
+
return false;
|
|
446
|
+
Rehash(slot_type, num_slots_bytes);
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
void Rehash() {
|
|
451
|
+
const size_t capacity = vector_.capacity();
|
|
452
|
+
const SlotType slot_type = GetSlotType(capacity);
|
|
453
|
+
const size_t num_slots_bytes = GetNumSlotsBytes(capacity, slot_type);
|
|
454
|
+
Rehash(slot_type, num_slots_bytes);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
void Rehash(SlotType slot_type, size_t num_slots_bytes) {
|
|
458
|
+
using key_type = key_type<T, GetKey>;
|
|
459
|
+
slot_type_ = slot_type;
|
|
460
|
+
slots_bytes_ = std::vector<uint8_t>(num_slots_bytes);
|
|
461
|
+
for (size_t i = 0; i < vector_.size();) {
|
|
462
|
+
const value_type& item = vector_[i];
|
|
463
|
+
const uint32_t key_hash = absl::Hash<key_type>{}(GetKey()(item));
|
|
464
|
+
++i;
|
|
465
|
+
PutSlot(key_hash, i, slot_type);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
void PutSlot(uint32_t key_hash, size_t next_index, SlotType slot_type) {
|
|
470
|
+
switch (slot_type) {
|
|
471
|
+
case SlotType::kUint8:
|
|
472
|
+
PutSlot<uint8_t>(key_hash, next_index);
|
|
473
|
+
break;
|
|
474
|
+
case SlotType::kUint16:
|
|
475
|
+
PutSlot<uint16_t>(key_hash, next_index);
|
|
476
|
+
break;
|
|
477
|
+
case SlotType::kUint32:
|
|
478
|
+
PutSlot<uint32_t>(key_hash, next_index);
|
|
479
|
+
break;
|
|
480
|
+
case SlotType::kUint64:
|
|
481
|
+
PutSlot<uint64_t>(key_hash, next_index);
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
template <typename SlotIntType>
|
|
487
|
+
void PutSlot(uint32_t key_hash, size_t next_index) {
|
|
488
|
+
const size_t num_slots = slots_bytes_.size() / sizeof(SlotIntType);
|
|
489
|
+
SlotIntType* slots = (SlotIntType*)slots_bytes_.data();
|
|
490
|
+
size_t slot_index = key_hash % num_slots;
|
|
491
|
+
while (true) {
|
|
492
|
+
SlotIntType& slot = slots[slot_index];
|
|
493
|
+
if (slot == 0) {
|
|
494
|
+
slot = next_index;
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
if (++slot_index == num_slots) {
|
|
498
|
+
slot_index = 0;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
template <typename Range>
|
|
504
|
+
void append_range_impl(const Range& range) {
|
|
505
|
+
reserve(capacity() + range.size());
|
|
506
|
+
for (const T& e : range) {
|
|
507
|
+
push_back(T(e));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
template <typename Range>
|
|
512
|
+
void append_range_impl(Range&& range) {
|
|
513
|
+
reserve(capacity() + range.size());
|
|
514
|
+
for (const T& e : range) {
|
|
515
|
+
push_back(std::move(const_cast<T&>(e)));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
template <typename K>
|
|
520
|
+
const T* absl_nullable find_or_null_impl(K key) const {
|
|
521
|
+
static_assert(std::is_same_v<K, key_type<T, GetKey>>);
|
|
522
|
+
ABSL_CHECK(!being_mutated_);
|
|
523
|
+
if (vector_.empty()) return nullptr;
|
|
524
|
+
const uint32_t key_hash = absl::Hash<K>{}(key);
|
|
525
|
+
switch (slot_type_) {
|
|
526
|
+
case SlotType::kUint8:
|
|
527
|
+
return FindOrNull<uint8_t>(key, key_hash);
|
|
528
|
+
case SlotType::kUint16:
|
|
529
|
+
return FindOrNull<uint16_t>(key, key_hash);
|
|
530
|
+
case SlotType::kUint32:
|
|
531
|
+
return FindOrNull<uint32_t>(key, key_hash);
|
|
532
|
+
default:
|
|
533
|
+
return FindOrNull<uint64_t>(key, key_hash);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
template <typename SlotIntType, typename K>
|
|
538
|
+
const T* absl_nullable FindOrNull(K key, uint32_t key_hash) const {
|
|
539
|
+
static_assert(std::is_same_v<K, key_type<T, GetKey>>);
|
|
540
|
+
const size_t num_slots = slots_bytes_.size() / sizeof(SlotIntType);
|
|
541
|
+
SlotIntType* slots = (SlotIntType*)slots_bytes_.data();
|
|
542
|
+
size_t slot_index = key_hash % num_slots;
|
|
543
|
+
while (true) {
|
|
544
|
+
const SlotIntType slot = slots[slot_index];
|
|
545
|
+
if (slot == 0) return nullptr;
|
|
546
|
+
const T& candidate = vector_[slot - 1];
|
|
547
|
+
if (GetKey()(candidate) == key) return &candidate;
|
|
548
|
+
if (++slot_index == num_slots) {
|
|
549
|
+
slot_index = 0;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
template <typename K>
|
|
555
|
+
const T& find_or_default_impl(K key) const {
|
|
556
|
+
static_assert(std::is_same_v<K, key_type<T, GetKey>>);
|
|
557
|
+
static const T* kDefaultValue = new T{};
|
|
558
|
+
return find_or_default_impl(key, *kDefaultValue);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
template <typename K>
|
|
562
|
+
const T& find_or_default_impl(K key, const T& default_value) const {
|
|
563
|
+
static_assert(std::is_same_v<K, key_type<T, GetKey>>);
|
|
564
|
+
const T* ptr = find_or_null_impl(key);
|
|
565
|
+
return ptr != nullptr ? *ptr : default_value;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
SlotType GetSlotType(size_t capacity) {
|
|
569
|
+
if (capacity <= std::numeric_limits<uint8_t>::max()) {
|
|
570
|
+
return SlotType::kUint8;
|
|
571
|
+
} else if (capacity <= std::numeric_limits<uint16_t>::max()) {
|
|
572
|
+
return SlotType::kUint16;
|
|
573
|
+
} else if (capacity <= std::numeric_limits<uint32_t>::max()) {
|
|
574
|
+
return SlotType::kUint32;
|
|
575
|
+
} else {
|
|
576
|
+
return SlotType::kUint64;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Returns the new size of slots_bytes_ for the given vector_'s capactiy.
|
|
581
|
+
static size_t GetNumSlotsBytes(size_t capacity, SlotType slot_type) {
|
|
582
|
+
constexpr int kNumSlotsPerItem = 2;
|
|
583
|
+
switch (slot_type) {
|
|
584
|
+
case SlotType::kUint8:
|
|
585
|
+
return capacity * kNumSlotsPerItem;
|
|
586
|
+
case SlotType::kUint16:
|
|
587
|
+
return capacity * kNumSlotsPerItem * 2;
|
|
588
|
+
case SlotType::kUint32:
|
|
589
|
+
if (std::is_same_v<size_t, uint32_t> &&
|
|
590
|
+
capacity >
|
|
591
|
+
std::numeric_limits<uint32_t>::max() / (kNumSlotsPerItem * 4)) {
|
|
592
|
+
return std::numeric_limits<uint32_t>::max();
|
|
593
|
+
}
|
|
594
|
+
return capacity * kNumSlotsPerItem * 4;
|
|
595
|
+
default:
|
|
596
|
+
return capacity * kNumSlotsPerItem * 8;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
friend class vector_mutator;
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
template <typename H, typename T, typename GetKey>
|
|
604
|
+
H AbslHashValue(H h, const keyed_items<T, GetKey>& keyed_items) {
|
|
605
|
+
return H::combine(std::move(h), keyed_items.vector());
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// A wrapper around a heap-allocated value of type T.
|
|
609
|
+
// In its zero-initialized state, the behavior of operator*() depends on whether
|
|
610
|
+
// it is called on a const rec<T> or a mutable rec<T>:
|
|
611
|
+
// - On a const rec<T>, operator*() returns a constant reference to a static
|
|
612
|
+
// zero-initialized T
|
|
613
|
+
// - On a mutable rec<T>, operator*() assigns a zero-initialized T to the rec
|
|
614
|
+
// and returns a mutable reference to it. The rec is no longer in a
|
|
615
|
+
// zero-initialized state.
|
|
616
|
+
//
|
|
617
|
+
// The skir C++ code generator can chose to make the field of a generated struct
|
|
618
|
+
// type a rec<T> instead of a T if T is a recursive type.
|
|
619
|
+
//
|
|
620
|
+
// For example:
|
|
621
|
+
//
|
|
622
|
+
// struct Foo {
|
|
623
|
+
// // Foo foo; // <- does not compile: a struct cannot contain itself
|
|
624
|
+
// rec<Foo> foo;
|
|
625
|
+
// std::string name;
|
|
626
|
+
// };
|
|
627
|
+
//
|
|
628
|
+
// The word 'rec' stands for 'recursive'.
|
|
629
|
+
template <typename T>
|
|
630
|
+
class rec {
|
|
631
|
+
public:
|
|
632
|
+
using value_type = T;
|
|
633
|
+
|
|
634
|
+
rec() = default;
|
|
635
|
+
rec(const rec& other) {
|
|
636
|
+
if (other.value_ != nullptr) {
|
|
637
|
+
value_ = std::make_unique<T>(*other.value_);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
rec(rec&& other) = default;
|
|
641
|
+
rec(T value) : value_(std::make_unique<T>(std::move(value))) {}
|
|
642
|
+
|
|
643
|
+
const T& operator*() const {
|
|
644
|
+
if (value_ != nullptr) {
|
|
645
|
+
return *value_;
|
|
646
|
+
} else {
|
|
647
|
+
static const T* const default_value = new T();
|
|
648
|
+
return *default_value;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
T& operator*() {
|
|
653
|
+
if (value_ != nullptr) {
|
|
654
|
+
return *value_;
|
|
655
|
+
} else {
|
|
656
|
+
return *(value_ = std::make_unique<T>());
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
operator const T&() const { return **this; }
|
|
661
|
+
operator T&() { return **this; }
|
|
662
|
+
|
|
663
|
+
const T* absl_nonnull operator->() const { return &(**this); }
|
|
664
|
+
T* absl_nonnull operator->() { return &(**this); }
|
|
665
|
+
|
|
666
|
+
rec& operator=(const rec& other) {
|
|
667
|
+
if (other.value_ != nullptr) {
|
|
668
|
+
value_ = std::make_unique<T>(*other.value_);
|
|
669
|
+
} else {
|
|
670
|
+
value_ = nullptr;
|
|
671
|
+
}
|
|
672
|
+
return *this;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
rec& operator=(rec&& other) = default;
|
|
676
|
+
|
|
677
|
+
rec& operator=(T other) {
|
|
678
|
+
value_ = std::make_unique<T>(std::move(other));
|
|
679
|
+
return *this;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
bool operator==(const rec& other) const {
|
|
683
|
+
return (value_ == nullptr && other.value_ == nullptr) || **this == *other;
|
|
684
|
+
}
|
|
685
|
+
bool operator!=(const rec& other) const { return !operator==(other); }
|
|
686
|
+
|
|
687
|
+
private:
|
|
688
|
+
std::unique_ptr<T> value_;
|
|
689
|
+
|
|
690
|
+
friend struct ::skir_internal::RecAdapter;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
template <typename T>
|
|
694
|
+
rec<T> make_rec(T value) {
|
|
695
|
+
return rec<T>(std::move(value));
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
template <typename O, typename T>
|
|
699
|
+
std::ostream& operator<<(std::ostream& os, const rec<T>& input) {
|
|
700
|
+
return os << *input;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
template <typename T>
|
|
704
|
+
class must_init {
|
|
705
|
+
public:
|
|
706
|
+
using value_type = T;
|
|
707
|
+
|
|
708
|
+
template <typename Value>
|
|
709
|
+
must_init(Value value) {
|
|
710
|
+
value_ = std::move(value);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
T operator*() && { return std::move(value_); }
|
|
714
|
+
|
|
715
|
+
private:
|
|
716
|
+
T value_;
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
template <typename T>
|
|
720
|
+
class must_init<std::vector<T>> {
|
|
721
|
+
public:
|
|
722
|
+
using value_type = std::vector<T>;
|
|
723
|
+
must_init(value_type value) { value_ = std::move(value); }
|
|
724
|
+
must_init(std::initializer_list<T> l) : must_init(value_type(std::move(l))) {}
|
|
725
|
+
value_type operator*() && { return std::move(value_); }
|
|
726
|
+
|
|
727
|
+
private:
|
|
728
|
+
value_type value_;
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
template <typename T, typename GetKey>
|
|
732
|
+
class must_init<skir::keyed_items<T, GetKey>> {
|
|
733
|
+
public:
|
|
734
|
+
using value_type = skir::keyed_items<T, GetKey>;
|
|
735
|
+
must_init(value_type value) { value_ = std::move(value); }
|
|
736
|
+
must_init(std::initializer_list<T> l) : must_init(value_type(std::move(l))) {}
|
|
737
|
+
value_type operator*() && { return std::move(value_); }
|
|
738
|
+
|
|
739
|
+
private:
|
|
740
|
+
value_type value_;
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
struct identity {
|
|
744
|
+
template <typename T>
|
|
745
|
+
T&& operator()(T&& t) const {
|
|
746
|
+
return std::forward<T>(t);
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
template <typename other = identity>
|
|
751
|
+
struct get_kind {
|
|
752
|
+
using other_type = other;
|
|
753
|
+
|
|
754
|
+
static constexpr absl::string_view kFieldName = "kind";
|
|
755
|
+
|
|
756
|
+
template <typename E>
|
|
757
|
+
auto operator()(const E& e) const {
|
|
758
|
+
return other()(e).kind();
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
namespace reflection {
|
|
763
|
+
|
|
764
|
+
enum class PrimitiveType {
|
|
765
|
+
kBool,
|
|
766
|
+
kInt32,
|
|
767
|
+
kInt64,
|
|
768
|
+
kUint64,
|
|
769
|
+
kFloat32,
|
|
770
|
+
kFloat64,
|
|
771
|
+
kTimestamp,
|
|
772
|
+
kString,
|
|
773
|
+
kBytes,
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
struct OptionalType;
|
|
777
|
+
struct ArrayType;
|
|
778
|
+
struct RecordType;
|
|
779
|
+
|
|
780
|
+
using Type = std::variant<PrimitiveType, OptionalType, ArrayType, RecordType>;
|
|
781
|
+
|
|
782
|
+
struct OptionalType {
|
|
783
|
+
skir::rec<Type> other;
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
struct ArrayType {
|
|
787
|
+
skir::rec<Type> item;
|
|
788
|
+
std::string key_extractor;
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
struct RecordType {
|
|
792
|
+
std::string record_id;
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
struct Field {
|
|
796
|
+
std::string name;
|
|
797
|
+
int number{};
|
|
798
|
+
Type type;
|
|
799
|
+
std::string doc;
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
struct Variant {
|
|
803
|
+
std::string name;
|
|
804
|
+
int number{};
|
|
805
|
+
// Present if this variant wraps a value.
|
|
806
|
+
std::optional<Type> type;
|
|
807
|
+
std::string doc;
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
struct get_name {
|
|
811
|
+
template <typename FieldOrVariant>
|
|
812
|
+
const std::string& operator()(const FieldOrVariant& f) {
|
|
813
|
+
return f.name;
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
// Definition of a skir struct.
|
|
818
|
+
struct Struct {
|
|
819
|
+
std::string id;
|
|
820
|
+
std::string doc;
|
|
821
|
+
keyed_items<Field, get_name> fields;
|
|
822
|
+
std::vector<int> removed_numbers;
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
// Definition of a skir struct.
|
|
826
|
+
struct Enum {
|
|
827
|
+
std::string id;
|
|
828
|
+
std::string doc;
|
|
829
|
+
keyed_items<Variant, get_name> variants;
|
|
830
|
+
std::vector<int> removed_numbers;
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
using Record = std::variant<Struct, Enum>;
|
|
834
|
+
|
|
835
|
+
struct get_id {
|
|
836
|
+
const std::string& operator()(const Record& record) const {
|
|
837
|
+
return std::visit([](const auto& r) -> const std::string& { return r.id; },
|
|
838
|
+
record);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
// Describes a skir type. Contains the definition of all the structs and enums
|
|
843
|
+
// referenced from the type.
|
|
844
|
+
//
|
|
845
|
+
// A TypeDescriptor can be serialized to JSON with AsJson(), and deserialized
|
|
846
|
+
// from JSON with FromJson().
|
|
847
|
+
struct TypeDescriptor {
|
|
848
|
+
Type type;
|
|
849
|
+
keyed_items<Record, get_id> records;
|
|
850
|
+
|
|
851
|
+
std::string AsJson() const;
|
|
852
|
+
|
|
853
|
+
static absl::StatusOr<TypeDescriptor> FromJson(absl::string_view json);
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
using RecordRegistry = keyed_items<Record, get_id>;
|
|
857
|
+
|
|
858
|
+
// For static reflection: represents a field of a skir struct.
|
|
859
|
+
// See `skir::reflection::ForEachField`
|
|
860
|
+
template <typename Getter, typename Value>
|
|
861
|
+
struct struct_field {
|
|
862
|
+
using getter_type = Getter;
|
|
863
|
+
using value_type = Value;
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
// For static reflection: represents a constant variant of a skir enum.
|
|
867
|
+
// See `skir::reflection::ForEachVariant`
|
|
868
|
+
template <typename Const>
|
|
869
|
+
struct enum_const_variant {
|
|
870
|
+
using const_type = Const;
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// For static reflection: represents a wrapper variant of a skir enum.
|
|
874
|
+
// See `skir::reflection::ForEachVariant`
|
|
875
|
+
template <typename Option, typename Value>
|
|
876
|
+
struct enum_wrapper_variant {
|
|
877
|
+
using option_type = Option;
|
|
878
|
+
using value_type = Value;
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
} // namespace reflection
|
|
882
|
+
|
|
883
|
+
namespace service {
|
|
884
|
+
|
|
885
|
+
enum class ResponseType {
|
|
886
|
+
// The method invocation succeeded and the response data is in JSON format.
|
|
887
|
+
kOkJson,
|
|
888
|
+
// The method invocation succeeded and the response data is in HTML format.
|
|
889
|
+
kOkHtml,
|
|
890
|
+
// The method invocation failed because the request was malformed.
|
|
891
|
+
// The response data is "bad-request:" followed by an error message.
|
|
892
|
+
kBadRequest,
|
|
893
|
+
// The method invocation resulted in an error on the server side.
|
|
894
|
+
// The response data is "server-error:" followed by an error message.
|
|
895
|
+
kServerError,
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// Raw response returned by the server.
|
|
899
|
+
struct RawResponse {
|
|
900
|
+
// The meaning of this string depends on the response type.
|
|
901
|
+
std::string data;
|
|
902
|
+
ResponseType type{};
|
|
903
|
+
|
|
904
|
+
int status_code() const {
|
|
905
|
+
switch (type) {
|
|
906
|
+
case ResponseType::kOkJson:
|
|
907
|
+
case ResponseType::kOkHtml:
|
|
908
|
+
return 200;
|
|
909
|
+
case ResponseType::kBadRequest:
|
|
910
|
+
return 400;
|
|
911
|
+
case ResponseType::kServerError:
|
|
912
|
+
return 500;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
absl::string_view content_type() const {
|
|
917
|
+
switch (type) {
|
|
918
|
+
case ResponseType::kOkJson: {
|
|
919
|
+
static const char kApplicationJson[] = "application/json";
|
|
920
|
+
return kApplicationJson;
|
|
921
|
+
}
|
|
922
|
+
case ResponseType::kOkHtml: {
|
|
923
|
+
static const char kTextHtml[] = "text/html";
|
|
924
|
+
return kTextHtml;
|
|
925
|
+
}
|
|
926
|
+
case ResponseType::kBadRequest:
|
|
927
|
+
case ResponseType::kServerError: {
|
|
928
|
+
static const char kTextPlain[] = "text/plain; charset=utf-8";
|
|
929
|
+
return kTextPlain;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
absl::StatusOr<std::string> AsStatus() && {
|
|
935
|
+
switch (type) {
|
|
936
|
+
case ResponseType::kOkJson:
|
|
937
|
+
case ResponseType::kOkHtml:
|
|
938
|
+
return std::move(data);
|
|
939
|
+
case ResponseType::kBadRequest:
|
|
940
|
+
case ResponseType::kServerError:
|
|
941
|
+
return absl::UnknownError(std::move(data));
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
|
|
946
|
+
class HttpHeaders {
|
|
947
|
+
public:
|
|
948
|
+
HttpHeaders() = default;
|
|
949
|
+
HttpHeaders(const HttpHeaders&) = default;
|
|
950
|
+
HttpHeaders(HttpHeaders&&) = default;
|
|
951
|
+
|
|
952
|
+
HttpHeaders& operator=(const HttpHeaders&) = default;
|
|
953
|
+
HttpHeaders& operator=(HttpHeaders&&) = default;
|
|
954
|
+
|
|
955
|
+
// Appends `value` to the vector of values associated with the given name
|
|
956
|
+
// converted to lowercase.
|
|
957
|
+
void Insert(absl::string_view name, absl::string_view value);
|
|
958
|
+
|
|
959
|
+
// Returns the vector of values associated with the given name converted to
|
|
960
|
+
// lowercase. If there is no value associated with the given name, returns an
|
|
961
|
+
// empty vector.
|
|
962
|
+
const std::vector<std::string>& Get(absl::string_view name) const;
|
|
963
|
+
|
|
964
|
+
// Returns the last value associated with the given name converted to
|
|
965
|
+
// lowercase, or an empty string if there is none.
|
|
966
|
+
absl::string_view GetLast(absl::string_view name) const;
|
|
967
|
+
|
|
968
|
+
// Returns a map view of this HttpHeaders object.
|
|
969
|
+
const absl::flat_hash_map<std::string, std::vector<std::string>>& map()
|
|
970
|
+
const {
|
|
971
|
+
return map_;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
private:
|
|
975
|
+
absl::flat_hash_map<std::string, std::vector<std::string>> map_;
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
// Sends RPCs to a skir service.
|
|
979
|
+
class Client {
|
|
980
|
+
public:
|
|
981
|
+
virtual ~Client() = default;
|
|
982
|
+
|
|
983
|
+
virtual absl::StatusOr<std::string> operator()(
|
|
984
|
+
absl::string_view request_data, const HttpHeaders& request_headers,
|
|
985
|
+
HttpHeaders& response_headers) const = 0;
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
} // namespace service
|
|
989
|
+
} // namespace skir
|
|
990
|
+
|
|
991
|
+
namespace skir_internal {
|
|
992
|
+
|
|
993
|
+
template <typename T>
|
|
994
|
+
T& get(T& input) {
|
|
995
|
+
return input;
|
|
996
|
+
}
|
|
997
|
+
template <typename T>
|
|
998
|
+
T& get(skir::rec<T>& input) {
|
|
999
|
+
return *input;
|
|
1000
|
+
}
|
|
1001
|
+
template <typename T>
|
|
1002
|
+
const T& get(const skir::rec<T>& input) {
|
|
1003
|
+
return *input;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
template <typename Struct, typename Getter>
|
|
1007
|
+
using struct_field =
|
|
1008
|
+
skir::reflection::struct_field<Getter, getter_value_type<Struct, Getter>>;
|
|
1009
|
+
|
|
1010
|
+
template <typename Enum, typename Option>
|
|
1011
|
+
using enum_wrapper_variant = skir::reflection::enum_wrapper_variant<
|
|
1012
|
+
Option, std::remove_const_t<std::remove_pointer_t<
|
|
1013
|
+
decltype(Option::get_or_null(std::declval<Enum&>()))>>>;
|
|
1014
|
+
|
|
1015
|
+
struct NewLine {
|
|
1016
|
+
public:
|
|
1017
|
+
const std::string& Indent() {
|
|
1018
|
+
new_line_ += {' ', ' '};
|
|
1019
|
+
return new_line_;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
const std::string& Dedent() {
|
|
1023
|
+
new_line_.resize(new_line_.length() - 2);
|
|
1024
|
+
return new_line_;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
const std::string& operator*() const { return new_line_; }
|
|
1028
|
+
|
|
1029
|
+
private:
|
|
1030
|
+
std::string new_line_ = "\n";
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
struct DenseJson {
|
|
1034
|
+
std::string out;
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
struct ReadableJson {
|
|
1038
|
+
std::string out;
|
|
1039
|
+
NewLine new_line;
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
struct DebugString {
|
|
1043
|
+
std::string out;
|
|
1044
|
+
NewLine new_line;
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
class ByteSink {
|
|
1048
|
+
public:
|
|
1049
|
+
ByteSink() = default;
|
|
1050
|
+
ByteSink(const ByteSink&) = delete;
|
|
1051
|
+
ByteSink(ByteSink&&) = delete;
|
|
1052
|
+
|
|
1053
|
+
~ByteSink() {
|
|
1054
|
+
if (data_ != nullptr) {
|
|
1055
|
+
delete[] data_;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
ByteSink& operator=(const ByteSink& other) = delete;
|
|
1060
|
+
ByteSink& operator=(ByteSink&& other) = delete;
|
|
1061
|
+
|
|
1062
|
+
size_t length() const { return pos_ - data_; }
|
|
1063
|
+
|
|
1064
|
+
// Invalidated by anything that can change the capacity of the byte sink.
|
|
1065
|
+
uint8_t* absl_nonnull data() { return data_; }
|
|
1066
|
+
// Invalidated by anything that can change the capacity of the byte sink.
|
|
1067
|
+
const uint8_t* absl_nonnull data() const { return data_; }
|
|
1068
|
+
|
|
1069
|
+
// Invalidated by anything that can change the capacity of the byte sink.
|
|
1070
|
+
uint8_t* absl_nonnull pos() { return pos_; }
|
|
1071
|
+
// The given pointer must be in the [data, data + length] range.
|
|
1072
|
+
void set_pos(uint8_t* absl_nonnull pos) { pos_ = pos; }
|
|
1073
|
+
|
|
1074
|
+
// Prepares for N bytes to be pushed with PushUnsafe().
|
|
1075
|
+
void Prepare(size_t n) {
|
|
1076
|
+
if (n <= capacity_left()) return;
|
|
1077
|
+
const size_t len = length();
|
|
1078
|
+
capacity_ += std::max(capacity_, n);
|
|
1079
|
+
uint8_t* new_data = new uint8_t[capacity_];
|
|
1080
|
+
std::memcpy(new_data, data_, len);
|
|
1081
|
+
delete[] data_;
|
|
1082
|
+
data_ = new_data;
|
|
1083
|
+
pos_ = data_ + len;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
void PushUnsafe(uint8_t byte) { *(pos_++) = byte; }
|
|
1087
|
+
|
|
1088
|
+
template <typename Byte, typename... Bytes>
|
|
1089
|
+
void PushUnsafe(uint8_t first, Byte second, Bytes... tail) {
|
|
1090
|
+
PushUnsafe(first);
|
|
1091
|
+
PushUnsafe(second, tail...);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
template <typename... Bytes>
|
|
1095
|
+
void Push(uint8_t first, Bytes... tail) {
|
|
1096
|
+
Prepare(1 + sizeof...(tail));
|
|
1097
|
+
PushUnsafe(first, tail...);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
void PushNUnsafe(const uint8_t* absl_nonnull src, size_t n) {
|
|
1101
|
+
std::memcpy((pos_ += n) - n, src, n);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
void PushN(const uint8_t* absl_nonnull src, size_t n) {
|
|
1105
|
+
Prepare(n);
|
|
1106
|
+
PushNUnsafe(src, n);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
void PushRangeUnsafe(const uint8_t* absl_nonnull begin,
|
|
1110
|
+
const uint8_t* absl_nonnull end) {
|
|
1111
|
+
PushNUnsafe(begin, end - begin);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
void PushRange(const uint8_t* absl_nonnull begin,
|
|
1115
|
+
const uint8_t* absl_nonnull end) {
|
|
1116
|
+
PushN(begin, end - begin);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
void PopN(size_t n) { pos_ -= n; }
|
|
1120
|
+
|
|
1121
|
+
::skir::ByteString ToByteString() && {
|
|
1122
|
+
::skir::ByteString byte_string(data_, length());
|
|
1123
|
+
// To prevent the ByteString destructor from deleting the array.
|
|
1124
|
+
data_ = nullptr;
|
|
1125
|
+
return byte_string;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
private:
|
|
1129
|
+
static constexpr size_t kDefaultCapacity = 16;
|
|
1130
|
+
size_t capacity_ = kDefaultCapacity;
|
|
1131
|
+
uint8_t* absl_nonnull data_ = new uint8_t[kDefaultCapacity];
|
|
1132
|
+
uint8_t* absl_nonnull pos_ = data_;
|
|
1133
|
+
|
|
1134
|
+
size_t capacity_left() const { return capacity_ - length(); }
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
struct ByteSource {
|
|
1138
|
+
ByteSource(const uint8_t* absl_nonnull begin, size_t length)
|
|
1139
|
+
: pos(begin), end(begin + length) {}
|
|
1140
|
+
ByteSource(const char* absl_nonnull begin, size_t length)
|
|
1141
|
+
: ByteSource((const uint8_t*)begin, length) {}
|
|
1142
|
+
|
|
1143
|
+
const uint8_t* absl_nonnull pos;
|
|
1144
|
+
const uint8_t* absl_nonnull const end;
|
|
1145
|
+
bool keep_unrecognized_values = false;
|
|
1146
|
+
bool error = false;
|
|
1147
|
+
|
|
1148
|
+
size_t num_bytes_left() const { return end - pos; }
|
|
1149
|
+
|
|
1150
|
+
uint8_t ReadWire() {
|
|
1151
|
+
if (pos < end) {
|
|
1152
|
+
return *(pos++);
|
|
1153
|
+
} else {
|
|
1154
|
+
RaiseError();
|
|
1155
|
+
return 0;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// Same as ReadWire, but does not increment pos.
|
|
1160
|
+
uint8_t PeekWire() {
|
|
1161
|
+
if (pos < end) {
|
|
1162
|
+
return *pos;
|
|
1163
|
+
} else {
|
|
1164
|
+
RaiseError();
|
|
1165
|
+
return 0;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
bool TryAdvance(size_t n) {
|
|
1170
|
+
if ((pos += n) <= end) return true;
|
|
1171
|
+
RaiseError();
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
void CheckEnd() {
|
|
1176
|
+
if (pos > end) {
|
|
1177
|
+
RaiseError();
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
void RaiseError() {
|
|
1182
|
+
pos = end;
|
|
1183
|
+
error = true;
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
enum class JsonTokenType {
|
|
1188
|
+
kError = '!',
|
|
1189
|
+
kTrue = 't',
|
|
1190
|
+
kFalse = 'f',
|
|
1191
|
+
kNull = 'n',
|
|
1192
|
+
kZero = '0',
|
|
1193
|
+
kUnsignedInteger = '+',
|
|
1194
|
+
kSignedInteger = '-',
|
|
1195
|
+
kFloat = '.',
|
|
1196
|
+
kString = '"',
|
|
1197
|
+
kLeftSquareBracket = '[',
|
|
1198
|
+
kRightSquareBracket = ']',
|
|
1199
|
+
kLeftCurlyBracket = '{',
|
|
1200
|
+
kRightCurlyBracket = '}',
|
|
1201
|
+
kComma = ',',
|
|
1202
|
+
kColon = ':',
|
|
1203
|
+
kStrEnd = '\0',
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
class JsonTokenizer {
|
|
1207
|
+
public:
|
|
1208
|
+
JsonTokenizer(const char* absl_nonnull json_code_begin,
|
|
1209
|
+
const char* absl_nonnull json_code_end,
|
|
1210
|
+
skir::UnrecognizedValuesPolicy unrecognized_values)
|
|
1211
|
+
: keep_unrecognized_values_(unrecognized_values ==
|
|
1212
|
+
skir::UnrecognizedValuesPolicy::kKeep) {
|
|
1213
|
+
state_.begin = json_code_begin;
|
|
1214
|
+
state_.end = json_code_end;
|
|
1215
|
+
state_.pos = json_code_begin;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
JsonTokenizer(const JsonTokenizer&) = delete;
|
|
1219
|
+
JsonTokenizer(JsonTokenizer&&) = delete;
|
|
1220
|
+
JsonTokenizer& operator=(const JsonTokenizer&) = delete;
|
|
1221
|
+
JsonTokenizer& operator=(JsonTokenizer&&) = delete;
|
|
1222
|
+
|
|
1223
|
+
JsonTokenType Next();
|
|
1224
|
+
|
|
1225
|
+
struct State {
|
|
1226
|
+
const char* absl_nullable begin = nullptr;
|
|
1227
|
+
const char* absl_nullable end = nullptr;
|
|
1228
|
+
// End position of the last token read, or 'begin' if no token was read.
|
|
1229
|
+
const char* absl_nullable pos = nullptr;
|
|
1230
|
+
// Begin position of the last token read, or nullptr if no token was read.
|
|
1231
|
+
const char* absl_nullable token_begin = nullptr;
|
|
1232
|
+
absl::Status status = absl::OkStatus();
|
|
1233
|
+
JsonTokenType token_type = JsonTokenType::kStrEnd;
|
|
1234
|
+
int64_t int_value = 0;
|
|
1235
|
+
uint64_t uint_value = 0;
|
|
1236
|
+
double float_value = 0.0;
|
|
1237
|
+
std::string string_value;
|
|
1238
|
+
|
|
1239
|
+
size_t chars_left() const { return end - pos; }
|
|
1240
|
+
|
|
1241
|
+
char NextCharOrNull() { return ++pos < end ? *pos : '\0'; }
|
|
1242
|
+
|
|
1243
|
+
void PushError(absl::string_view message);
|
|
1244
|
+
void PushErrorAtPosition(absl::string_view expected);
|
|
1245
|
+
void PushUnexpectedTokenError(absl::string_view expected);
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
State& mutable_state() { return state_; }
|
|
1249
|
+
const State& state() const { return state_; }
|
|
1250
|
+
|
|
1251
|
+
const bool keep_unrecognized_values() const {
|
|
1252
|
+
return keep_unrecognized_values_;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
private:
|
|
1256
|
+
const bool keep_unrecognized_values_;
|
|
1257
|
+
State state_;
|
|
1258
|
+
};
|
|
1259
|
+
|
|
1260
|
+
void SkipValue(JsonTokenizer& tokenizer);
|
|
1261
|
+
|
|
1262
|
+
class JsonArrayCloser {
|
|
1263
|
+
public:
|
|
1264
|
+
explicit JsonArrayCloser(DenseJson* absl_nonnull json) : json_(json->out) {}
|
|
1265
|
+
~JsonArrayCloser() { json_ += ']'; }
|
|
1266
|
+
|
|
1267
|
+
private:
|
|
1268
|
+
std::string& json_;
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
class JsonArrayReader {
|
|
1272
|
+
public:
|
|
1273
|
+
explicit JsonArrayReader(JsonTokenizer* absl_nonnull tokenizer);
|
|
1274
|
+
bool NextElement();
|
|
1275
|
+
JsonTokenizer& tokenizer() { return tokenizer_; }
|
|
1276
|
+
|
|
1277
|
+
private:
|
|
1278
|
+
JsonTokenizer& tokenizer_;
|
|
1279
|
+
bool zero_state_ = true;
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
class JsonObjectReader {
|
|
1283
|
+
public:
|
|
1284
|
+
explicit JsonObjectReader(JsonTokenizer* absl_nonnull tokenizer);
|
|
1285
|
+
|
|
1286
|
+
bool NextEntry();
|
|
1287
|
+
|
|
1288
|
+
// Name component of the current entry.
|
|
1289
|
+
// Invalidated when NextEntry() is called.
|
|
1290
|
+
const std::string& name() const { return name_; }
|
|
1291
|
+
|
|
1292
|
+
private:
|
|
1293
|
+
JsonTokenizer& tokenizer_;
|
|
1294
|
+
std::string name_;
|
|
1295
|
+
bool zero_state_ = true;
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
void SkipValue(ByteSource& source);
|
|
1299
|
+
|
|
1300
|
+
void AppendArrayPrefix(size_t length, ByteSink& out);
|
|
1301
|
+
|
|
1302
|
+
void ParseArrayPrefix(ByteSource& source, uint32_t& length);
|
|
1303
|
+
|
|
1304
|
+
template <typename T>
|
|
1305
|
+
struct skir_type {};
|
|
1306
|
+
|
|
1307
|
+
struct BoolAdapter {
|
|
1308
|
+
static bool IsDefault(bool input) { return !input; }
|
|
1309
|
+
|
|
1310
|
+
static void Append(bool input, DenseJson& out) {
|
|
1311
|
+
out.out += input ? '1' : '0';
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
static void Append(bool input, ReadableJson& out) {
|
|
1315
|
+
AppendTrueOrFalse(input, out.out);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
static void Append(bool input, DebugString& out) {
|
|
1319
|
+
AppendTrueOrFalse(input, out.out);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
static void Append(bool input, ByteSink& out) { out.Push(input ? 1 : 0); }
|
|
1323
|
+
|
|
1324
|
+
static void Parse(JsonTokenizer& tokenizer, bool& out);
|
|
1325
|
+
|
|
1326
|
+
static void Parse(ByteSource& source, bool& out);
|
|
1327
|
+
|
|
1328
|
+
static skir::reflection::Type GetType(skir_type<bool>) {
|
|
1329
|
+
return skir::reflection::PrimitiveType::kBool;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
static void RegisterRecords(skir_type<bool>,
|
|
1333
|
+
skir::reflection::RecordRegistry&) {}
|
|
1334
|
+
|
|
1335
|
+
static constexpr bool IsStruct() { return false; }
|
|
1336
|
+
static constexpr bool IsEnum() { return false; }
|
|
1337
|
+
|
|
1338
|
+
private:
|
|
1339
|
+
static void AppendTrueOrFalse(bool input, std::string& out) {
|
|
1340
|
+
if (input) {
|
|
1341
|
+
out += {'t', 'r', 'u', 'e'};
|
|
1342
|
+
} else {
|
|
1343
|
+
out += {'f', 'a', 'l', 's', 'e'};
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
struct Int32Adapter {
|
|
1349
|
+
static bool IsDefault(int32_t input) { return !input; }
|
|
1350
|
+
|
|
1351
|
+
template <typename Out>
|
|
1352
|
+
static void Append(int32_t input, Out& out) {
|
|
1353
|
+
absl::StrAppend(&out.out, input);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
static void Append(int32_t input, ByteSink& out);
|
|
1357
|
+
|
|
1358
|
+
static void Parse(JsonTokenizer& tokenizer, int32_t& out);
|
|
1359
|
+
static void Parse(ByteSource& source, int32_t& out);
|
|
1360
|
+
|
|
1361
|
+
static skir::reflection::Type GetType(skir_type<int32_t>) {
|
|
1362
|
+
return skir::reflection::PrimitiveType::kInt32;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
static void RegisterRecords(skir_type<int32_t>,
|
|
1366
|
+
skir::reflection::RecordRegistry&) {}
|
|
1367
|
+
|
|
1368
|
+
static constexpr bool IsStruct() { return false; }
|
|
1369
|
+
static constexpr bool IsEnum() { return false; }
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
constexpr int64_t kMinSafeJavascriptInt = -9007199254740991; // -(2 ^ 53 - 1)
|
|
1373
|
+
constexpr int64_t kMaxSafeJavascriptInt = 9007199254740991; // 2 ^ 53 - 1
|
|
1374
|
+
|
|
1375
|
+
struct Int64Adapter {
|
|
1376
|
+
static bool IsDefault(int64_t input) { return !input; }
|
|
1377
|
+
|
|
1378
|
+
template <typename Out>
|
|
1379
|
+
static void Append(int64_t input, Out& out) {
|
|
1380
|
+
if (skir_internal::kMinSafeJavascriptInt <= input &&
|
|
1381
|
+
input <= skir_internal::kMaxSafeJavascriptInt) {
|
|
1382
|
+
absl::StrAppend(&out.out, input);
|
|
1383
|
+
} else {
|
|
1384
|
+
out.out += '"';
|
|
1385
|
+
absl::StrAppend(&out.out, input);
|
|
1386
|
+
out.out += '"';
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
static void Append(int64_t input, DebugString& out) {
|
|
1391
|
+
absl::StrAppend(&out.out, input);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
static void Append(int64_t input, ByteSink& out);
|
|
1395
|
+
static void Parse(JsonTokenizer& tokenizer, int64_t& out);
|
|
1396
|
+
static void Parse(ByteSource& source, int64_t& out);
|
|
1397
|
+
|
|
1398
|
+
static skir::reflection::Type GetType(skir_type<int64_t>) {
|
|
1399
|
+
return skir::reflection::PrimitiveType::kInt64;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
static void RegisterRecords(skir_type<int64_t>,
|
|
1403
|
+
skir::reflection::RecordRegistry&) {}
|
|
1404
|
+
|
|
1405
|
+
static constexpr bool IsStruct() { return false; }
|
|
1406
|
+
static constexpr bool IsEnum() { return false; }
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
struct Uint64Adapter {
|
|
1410
|
+
static bool IsDefault(uint64_t input) { return !input; }
|
|
1411
|
+
|
|
1412
|
+
template <typename Out>
|
|
1413
|
+
static void Append(uint64_t input, Out& out) {
|
|
1414
|
+
if (input <= skir_internal::kMaxSafeJavascriptInt) {
|
|
1415
|
+
absl::StrAppend(&out.out, input);
|
|
1416
|
+
} else {
|
|
1417
|
+
out.out += '"';
|
|
1418
|
+
absl::StrAppend(&out.out, input);
|
|
1419
|
+
out.out += '"';
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
static void Append(int64_t input, DebugString& out) {
|
|
1424
|
+
absl::StrAppend(&out.out, input);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
static void Append(uint64_t input, ByteSink& out);
|
|
1428
|
+
static void Parse(JsonTokenizer& tokenizer, uint64_t& out);
|
|
1429
|
+
static void Parse(ByteSource& source, uint64_t& out);
|
|
1430
|
+
|
|
1431
|
+
static skir::reflection::Type GetType(skir_type<uint64_t>) {
|
|
1432
|
+
return skir::reflection::PrimitiveType::kUint64;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
static void RegisterRecords(skir_type<uint64_t>,
|
|
1436
|
+
skir::reflection::RecordRegistry&) {}
|
|
1437
|
+
|
|
1438
|
+
static constexpr bool IsStruct() { return false; }
|
|
1439
|
+
static constexpr bool IsEnum() { return false; }
|
|
1440
|
+
};
|
|
1441
|
+
|
|
1442
|
+
template <typename float_or_double>
|
|
1443
|
+
void AppendJsonForFloat(float_or_double input, std::string& out) {
|
|
1444
|
+
if (std::isfinite(input)) {
|
|
1445
|
+
absl::StrAppend(&out, input);
|
|
1446
|
+
} else if (std::isinf(input)) {
|
|
1447
|
+
if (input < 0) {
|
|
1448
|
+
out += {'"', '-', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y', '"'};
|
|
1449
|
+
} else {
|
|
1450
|
+
out += {'"', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y', '"'};
|
|
1451
|
+
}
|
|
1452
|
+
} else {
|
|
1453
|
+
out += {'"', 'N', 'a', 'N', '"'};
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
struct Float32Adapter {
|
|
1458
|
+
static bool IsDefault(float input) { return !input; }
|
|
1459
|
+
|
|
1460
|
+
template <typename Out>
|
|
1461
|
+
static void Append(float input, Out& out) {
|
|
1462
|
+
AppendJsonForFloat(input, out.out);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
static void Append(float input, DebugString& out) {
|
|
1466
|
+
if (std::isfinite(input)) {
|
|
1467
|
+
absl::StrAppend(&out.out, input);
|
|
1468
|
+
} else if (std::isinf(input)) {
|
|
1469
|
+
if (input < 0) {
|
|
1470
|
+
out.out += "-std::numeric_limits<float>::infinity()";
|
|
1471
|
+
} else {
|
|
1472
|
+
out.out += "std::numeric_limits<float>::infinity()";
|
|
1473
|
+
}
|
|
1474
|
+
} else {
|
|
1475
|
+
out.out += "std::numeric_limits<float>::quiet_NaN()";
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
static void Append(float input, ByteSink& out);
|
|
1480
|
+
static void Parse(JsonTokenizer& tokenizer, float& out);
|
|
1481
|
+
static void Parse(ByteSource& source, float& out);
|
|
1482
|
+
|
|
1483
|
+
static skir::reflection::Type GetType(skir_type<float>) {
|
|
1484
|
+
return skir::reflection::PrimitiveType::kFloat32;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
static void RegisterRecords(skir_type<float>,
|
|
1488
|
+
skir::reflection::RecordRegistry&) {}
|
|
1489
|
+
|
|
1490
|
+
static constexpr bool IsStruct() { return false; }
|
|
1491
|
+
static constexpr bool IsEnum() { return false; }
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
struct Float64Adapter {
|
|
1495
|
+
static bool IsDefault(double input) { return !input; }
|
|
1496
|
+
|
|
1497
|
+
template <typename Out>
|
|
1498
|
+
static void Append(double input, Out& out) {
|
|
1499
|
+
AppendJsonForFloat(input, out.out);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
static void Append(double input, DebugString& out) {
|
|
1503
|
+
if (std::isfinite(input)) {
|
|
1504
|
+
absl::StrAppend(&out.out, input);
|
|
1505
|
+
} else if (std::isinf(input)) {
|
|
1506
|
+
if (input < 0) {
|
|
1507
|
+
out.out += "-std::numeric_limits<double>::infinity()";
|
|
1508
|
+
} else {
|
|
1509
|
+
out.out += "std::numeric_limits<double>::infinity()";
|
|
1510
|
+
}
|
|
1511
|
+
} else {
|
|
1512
|
+
out.out += "std::numeric_limits<double>::quiet_NaN()";
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
static void Append(double input, ByteSink& out);
|
|
1517
|
+
static void Parse(JsonTokenizer& tokenizer, double& out);
|
|
1518
|
+
static void Parse(ByteSource& source, double& out);
|
|
1519
|
+
|
|
1520
|
+
static skir::reflection::Type GetType(skir_type<double>) {
|
|
1521
|
+
return skir::reflection::PrimitiveType::kFloat64;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
static void RegisterRecords(skir_type<double>,
|
|
1525
|
+
skir::reflection::RecordRegistry&) {}
|
|
1526
|
+
|
|
1527
|
+
static constexpr bool IsStruct() { return false; }
|
|
1528
|
+
static constexpr bool IsEnum() { return false; }
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
struct TimestampAdapter {
|
|
1532
|
+
static bool IsDefault(absl::Time input) { return !absl::ToUnixMillis(input); }
|
|
1533
|
+
|
|
1534
|
+
static void Append(absl::Time input, DenseJson& out);
|
|
1535
|
+
static void Append(absl::Time input, ReadableJson& out);
|
|
1536
|
+
static void Append(absl::Time input, DebugString& out);
|
|
1537
|
+
static void Append(absl::Time input, ByteSink& out);
|
|
1538
|
+
static void Parse(JsonTokenizer& tokenizer, absl::Time& out);
|
|
1539
|
+
static void Parse(ByteSource& source, absl::Time& out);
|
|
1540
|
+
|
|
1541
|
+
static skir::reflection::Type GetType(skir_type<absl::Time>) {
|
|
1542
|
+
return skir::reflection::PrimitiveType::kTimestamp;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
static void RegisterRecords(skir_type<absl::Time>,
|
|
1546
|
+
skir::reflection::RecordRegistry&) {}
|
|
1547
|
+
|
|
1548
|
+
static constexpr bool IsStruct() { return false; }
|
|
1549
|
+
static constexpr bool IsEnum() { return false; }
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
struct StringAdapter {
|
|
1553
|
+
static bool IsDefault(const std::string& input) { return input.empty(); }
|
|
1554
|
+
|
|
1555
|
+
template <typename Out>
|
|
1556
|
+
static void Append(const std::string& input, Out& out) {
|
|
1557
|
+
AppendJson(input, out.out);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
static void AppendJson(const std::string& input, std::string& out);
|
|
1561
|
+
static void Append(const std::string& input, DebugString& out);
|
|
1562
|
+
static void Append(const std::string& input, ByteSink& out);
|
|
1563
|
+
static void Parse(JsonTokenizer& tokenizer, std::string& out);
|
|
1564
|
+
static void Parse(ByteSource& source, std::string& out);
|
|
1565
|
+
|
|
1566
|
+
static skir::reflection::Type GetType(skir_type<std::string>) {
|
|
1567
|
+
return skir::reflection::PrimitiveType::kString;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
static void RegisterRecords(skir_type<std::string>,
|
|
1571
|
+
skir::reflection::RecordRegistry&) {}
|
|
1572
|
+
|
|
1573
|
+
static constexpr bool IsStruct() { return false; }
|
|
1574
|
+
static constexpr bool IsEnum() { return false; }
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1577
|
+
struct BytesAdapter {
|
|
1578
|
+
static bool IsDefault(const skir::ByteString& input) { return input.empty(); }
|
|
1579
|
+
|
|
1580
|
+
static void Append(const skir::ByteString&, DenseJson& out);
|
|
1581
|
+
static void Append(const skir::ByteString&, ReadableJson& out);
|
|
1582
|
+
static void Append(const skir::ByteString& input, DebugString& out);
|
|
1583
|
+
static void Append(const skir::ByteString& input, ByteSink& out);
|
|
1584
|
+
static void Parse(JsonTokenizer& tokenizer, skir::ByteString& out);
|
|
1585
|
+
static void Parse(ByteSource& source, skir::ByteString& out);
|
|
1586
|
+
|
|
1587
|
+
static skir::reflection::Type GetType(skir_type<skir::ByteString>) {
|
|
1588
|
+
return skir::reflection::PrimitiveType::kBytes;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
static void RegisterRecords(skir_type<skir::ByteString>,
|
|
1592
|
+
skir::reflection::RecordRegistry&) {}
|
|
1593
|
+
|
|
1594
|
+
static constexpr bool IsStruct() { return false; }
|
|
1595
|
+
static constexpr bool IsEnum() { return false; }
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
template <typename T>
|
|
1599
|
+
void GetAdapter(skir_type<T>) {
|
|
1600
|
+
static_assert(false, "not a skir type");
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
inline BoolAdapter GetAdapter(skir_type<bool>);
|
|
1604
|
+
inline Int32Adapter GetAdapter(skir_type<int32_t>);
|
|
1605
|
+
inline Int64Adapter GetAdapter(skir_type<int64_t>);
|
|
1606
|
+
inline Uint64Adapter GetAdapter(skir_type<uint64_t>);
|
|
1607
|
+
inline Float32Adapter GetAdapter(skir_type<float>);
|
|
1608
|
+
inline Float64Adapter GetAdapter(skir_type<double>);
|
|
1609
|
+
inline TimestampAdapter GetAdapter(skir_type<absl::Time>);
|
|
1610
|
+
inline StringAdapter GetAdapter(skir_type<std::string>);
|
|
1611
|
+
inline BytesAdapter GetAdapter(skir_type<skir::ByteString>);
|
|
1612
|
+
|
|
1613
|
+
// =============================================================================
|
|
1614
|
+
// BEGIN serialization of type descriptors
|
|
1615
|
+
// =============================================================================
|
|
1616
|
+
|
|
1617
|
+
struct ReflectionTypeAdapter {
|
|
1618
|
+
static bool IsDefault(const skir::reflection::Type& input) { return false; }
|
|
1619
|
+
static void Append(const skir::reflection::Type& input, ReadableJson& out);
|
|
1620
|
+
static void Parse(JsonTokenizer& tokenizer, skir::reflection::Type& out);
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
struct ReflectionPrimitiveTypeAdapter {
|
|
1624
|
+
static bool IsDefault(skir::reflection::PrimitiveType input) { return false; }
|
|
1625
|
+
static void Append(skir::reflection::PrimitiveType input, ReadableJson& out);
|
|
1626
|
+
static void Parse(JsonTokenizer& tokenizer,
|
|
1627
|
+
skir::reflection::PrimitiveType& out);
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
struct ReflectionOptionalTypeAdapter {
|
|
1631
|
+
static bool IsDefault(const skir::reflection::OptionalType& input) {
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1634
|
+
static void Append(const skir::reflection::OptionalType& input,
|
|
1635
|
+
ReadableJson& out);
|
|
1636
|
+
static void Parse(JsonTokenizer& tokenizer,
|
|
1637
|
+
skir::reflection::OptionalType& out);
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1640
|
+
struct ReflectionArrayTypeAdapter {
|
|
1641
|
+
static bool IsDefault(const skir::reflection::ArrayType& input) {
|
|
1642
|
+
return false;
|
|
1643
|
+
}
|
|
1644
|
+
static void Append(const skir::reflection::ArrayType& input,
|
|
1645
|
+
ReadableJson& out);
|
|
1646
|
+
static void Parse(JsonTokenizer& tokenizer, skir::reflection::ArrayType& out);
|
|
1647
|
+
};
|
|
1648
|
+
|
|
1649
|
+
struct ReflectionRecordTypeAdapter {
|
|
1650
|
+
static bool IsDefault(const skir::reflection::RecordType& input) {
|
|
1651
|
+
return false;
|
|
1652
|
+
}
|
|
1653
|
+
static void Append(const skir::reflection::RecordType& input,
|
|
1654
|
+
ReadableJson& out);
|
|
1655
|
+
static void Parse(JsonTokenizer& tokenizer,
|
|
1656
|
+
skir::reflection::RecordType& out);
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
struct ReflectionFieldAdapter {
|
|
1660
|
+
static bool IsDefault(const skir::reflection::Field&) { return false; }
|
|
1661
|
+
static void Append(const skir::reflection::Field& input, ReadableJson& out);
|
|
1662
|
+
static void Parse(JsonTokenizer& tokenizer, skir::reflection::Field& out);
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
struct ReflectionVariantAdapter {
|
|
1666
|
+
static bool IsDefault(const skir::reflection::Variant&) { return false; }
|
|
1667
|
+
static void Append(const skir::reflection::Variant& input, ReadableJson& out);
|
|
1668
|
+
static void Parse(JsonTokenizer& tokenizer, skir::reflection::Variant& out);
|
|
1669
|
+
};
|
|
1670
|
+
|
|
1671
|
+
struct ReflectionRecordAdapter {
|
|
1672
|
+
static bool IsDefault(const skir::reflection::Record& input) { return false; }
|
|
1673
|
+
static void Append(const skir::reflection::Record& input, ReadableJson& out);
|
|
1674
|
+
static void Parse(JsonTokenizer& tokenizer, skir::reflection::Record& out);
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
struct ReflectionTypeDescriptorAdapter {
|
|
1678
|
+
static bool IsDefault(const skir::reflection::TypeDescriptor& input) {
|
|
1679
|
+
return false;
|
|
1680
|
+
}
|
|
1681
|
+
static void Append(const skir::reflection::TypeDescriptor& input,
|
|
1682
|
+
ReadableJson& out);
|
|
1683
|
+
static void Parse(JsonTokenizer& tokenizer,
|
|
1684
|
+
skir::reflection::TypeDescriptor& out);
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
inline ReflectionTypeAdapter GetAdapter(skir_type<skir::reflection::Type>);
|
|
1688
|
+
inline ReflectionPrimitiveTypeAdapter GetAdapter(
|
|
1689
|
+
skir_type<skir::reflection::PrimitiveType>);
|
|
1690
|
+
inline ReflectionOptionalTypeAdapter GetAdapter(
|
|
1691
|
+
skir_type<skir::reflection::OptionalType>);
|
|
1692
|
+
inline ReflectionArrayTypeAdapter GetAdapter(
|
|
1693
|
+
skir_type<skir::reflection::ArrayType>);
|
|
1694
|
+
inline ReflectionRecordTypeAdapter GetAdapter(
|
|
1695
|
+
skir_type<skir::reflection::RecordType>);
|
|
1696
|
+
inline ReflectionFieldAdapter GetAdapter(skir_type<skir::reflection::Field>);
|
|
1697
|
+
inline ReflectionVariantAdapter GetAdapter(
|
|
1698
|
+
skir_type<skir::reflection::Variant>);
|
|
1699
|
+
inline ReflectionRecordAdapter GetAdapter(skir_type<skir::reflection::Record>);
|
|
1700
|
+
inline ReflectionTypeDescriptorAdapter GetAdapter(
|
|
1701
|
+
skir_type<skir::reflection::TypeDescriptor>);
|
|
1702
|
+
|
|
1703
|
+
// =============================================================================
|
|
1704
|
+
// END serialization of type descriptors
|
|
1705
|
+
// =============================================================================
|
|
1706
|
+
|
|
1707
|
+
template <typename T>
|
|
1708
|
+
using TypeAdapter = decltype(GetAdapter(skir_type<T>()));
|
|
1709
|
+
|
|
1710
|
+
template <typename T>
|
|
1711
|
+
bool IsDefault(const T& input) {
|
|
1712
|
+
return TypeAdapter<T>::IsDefault(input);
|
|
1713
|
+
}
|
|
1714
|
+
template <typename T, typename Out>
|
|
1715
|
+
void Append(const T& input, Out& out) {
|
|
1716
|
+
TypeAdapter<T>::Append(input, out);
|
|
1717
|
+
}
|
|
1718
|
+
template <typename Source, typename T>
|
|
1719
|
+
void Parse(Source& source, T& out) {
|
|
1720
|
+
TypeAdapter<T>::Parse(source, out);
|
|
1721
|
+
}
|
|
1722
|
+
template <typename T>
|
|
1723
|
+
skir::reflection::Type GetType() {
|
|
1724
|
+
return TypeAdapter<T>::GetType(skir_type<T>());
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
template <typename T>
|
|
1728
|
+
void RegisterRecords(skir::reflection::RecordRegistry& registry) {
|
|
1729
|
+
TypeAdapter<T>::RegisterRecords(skir_type<T>(), registry);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
template <typename T>
|
|
1733
|
+
std::string ToDebugString(const T& input) {
|
|
1734
|
+
static_assert(!std::is_pointer<T>::value,
|
|
1735
|
+
"Can't pass a pointer to ToDebugString");
|
|
1736
|
+
skir_internal::DebugString result;
|
|
1737
|
+
Append(input, result);
|
|
1738
|
+
return result.out;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
inline std::string ToDebugString(const char* absl_nonnull input) {
|
|
1742
|
+
return ToDebugString(std::string(input));
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
template <typename T>
|
|
1746
|
+
std::false_type is_optional(T) {
|
|
1747
|
+
return std::false_type();
|
|
1748
|
+
}
|
|
1749
|
+
template <typename T>
|
|
1750
|
+
std::true_type is_optional(absl::optional<T>) {
|
|
1751
|
+
return std::true_type();
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
struct OptionalAdapter {
|
|
1755
|
+
template <typename T>
|
|
1756
|
+
static bool IsDefault(const absl::optional<T>& input) {
|
|
1757
|
+
static_assert(
|
|
1758
|
+
std::is_same<decltype(is_optional(T())), std::false_type>::value);
|
|
1759
|
+
return !input.has_value();
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
template <typename T, typename Out>
|
|
1763
|
+
static void Append(const absl::optional<T>& input, Out& out) {
|
|
1764
|
+
if (input.has_value()) {
|
|
1765
|
+
TypeAdapter<T>::Append(*input, out);
|
|
1766
|
+
} else {
|
|
1767
|
+
out.out += {'n', 'u', 'l', 'l'};
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
template <typename T>
|
|
1772
|
+
static void Append(const absl::optional<T>& input, DebugString& out) {
|
|
1773
|
+
if (input.has_value()) {
|
|
1774
|
+
out.out += "absl::make_optional(";
|
|
1775
|
+
TypeAdapter<T>::Append(*input, out);
|
|
1776
|
+
out.out += ')';
|
|
1777
|
+
} else {
|
|
1778
|
+
out.out += "absl::nullopt";
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
template <typename T>
|
|
1783
|
+
static void Append(const absl::optional<T>& input, ByteSink& out) {
|
|
1784
|
+
if (input.has_value()) {
|
|
1785
|
+
TypeAdapter<T>::Append(*input, out);
|
|
1786
|
+
} else {
|
|
1787
|
+
out.Push(255);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
template <typename T>
|
|
1792
|
+
static void Parse(JsonTokenizer& tokenizer, absl::optional<T>& out) {
|
|
1793
|
+
if (tokenizer.state().token_type == JsonTokenType::kNull) {
|
|
1794
|
+
tokenizer.Next();
|
|
1795
|
+
} else {
|
|
1796
|
+
skir_internal::Parse(tokenizer, out.emplace());
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
template <typename T>
|
|
1801
|
+
static void Parse(ByteSource& source, absl::optional<T>& out) {
|
|
1802
|
+
if (source.PeekWire() == 255) {
|
|
1803
|
+
++(source.pos);
|
|
1804
|
+
} else {
|
|
1805
|
+
TypeAdapter<T>::Parse(source, out.emplace());
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
template <typename T>
|
|
1810
|
+
static skir::reflection::Type GetType(skir_type<absl::optional<T>>) {
|
|
1811
|
+
return skir::reflection::OptionalType{skir_internal::GetType<T>()};
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
template <typename T>
|
|
1815
|
+
static void RegisterRecords(skir_type<absl::optional<T>>,
|
|
1816
|
+
skir::reflection::RecordRegistry& registry) {
|
|
1817
|
+
skir_internal::RegisterRecords<T>(registry);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
static constexpr bool IsStruct() { return false; }
|
|
1821
|
+
static constexpr bool IsEnum() { return false; }
|
|
1822
|
+
};
|
|
1823
|
+
|
|
1824
|
+
template <typename T>
|
|
1825
|
+
inline OptionalAdapter GetAdapter(skir_type<absl::optional<T>>);
|
|
1826
|
+
|
|
1827
|
+
template <typename GetKey>
|
|
1828
|
+
void MakeKeyChain(std::vector<std::string>& out) {
|
|
1829
|
+
using other_type = typename GetKey::other_type;
|
|
1830
|
+
MakeKeyChain<other_type>(out);
|
|
1831
|
+
out.emplace_back(GetKey::kFieldName);
|
|
1832
|
+
}
|
|
1833
|
+
template <>
|
|
1834
|
+
inline void MakeKeyChain<skir::identity>(std::vector<std::string>& out) {}
|
|
1835
|
+
|
|
1836
|
+
struct ArrayAdapter {
|
|
1837
|
+
template <typename Input>
|
|
1838
|
+
static bool IsDefault(const Input& input) {
|
|
1839
|
+
return input.empty();
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
template <typename Input>
|
|
1843
|
+
static void Append(const Input& input, DenseJson& out) {
|
|
1844
|
+
using T = typename Input::value_type;
|
|
1845
|
+
if (input.empty()) {
|
|
1846
|
+
out.out += {'[', ']'};
|
|
1847
|
+
} else {
|
|
1848
|
+
out.out += '[';
|
|
1849
|
+
TypeAdapter<T>::Append(input[0], out);
|
|
1850
|
+
for (size_t i = 1; i < input.size(); ++i) {
|
|
1851
|
+
out.out += ',';
|
|
1852
|
+
TypeAdapter<T>::Append(input[i], out);
|
|
1853
|
+
}
|
|
1854
|
+
out.out += ']';
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
template <typename Input>
|
|
1859
|
+
static void Append(const Input& input, ReadableJson& out) {
|
|
1860
|
+
using T = typename Input::value_type;
|
|
1861
|
+
if (input.empty()) {
|
|
1862
|
+
out.out += {'[', ']'};
|
|
1863
|
+
} else {
|
|
1864
|
+
out.out += '[';
|
|
1865
|
+
out.out += out.new_line.Indent();
|
|
1866
|
+
TypeAdapter<T>::Append(input[0], out);
|
|
1867
|
+
for (size_t i = 1; i < input.size(); ++i) {
|
|
1868
|
+
out.out += ',';
|
|
1869
|
+
out.out += *out.new_line;
|
|
1870
|
+
TypeAdapter<T>::Append(input[i], out);
|
|
1871
|
+
}
|
|
1872
|
+
out.out += out.new_line.Dedent();
|
|
1873
|
+
out.out += ']';
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
template <typename Input>
|
|
1878
|
+
static void Append(const Input& input, DebugString& out) {
|
|
1879
|
+
using T = typename Input::value_type;
|
|
1880
|
+
if (input.empty()) {
|
|
1881
|
+
out.out += {'{', '}'};
|
|
1882
|
+
} else {
|
|
1883
|
+
out.out += '{';
|
|
1884
|
+
out.new_line.Indent();
|
|
1885
|
+
for (const T& element : input) {
|
|
1886
|
+
out.out += *out.new_line;
|
|
1887
|
+
TypeAdapter<T>::Append(element, out);
|
|
1888
|
+
out.out += ',';
|
|
1889
|
+
}
|
|
1890
|
+
out.out += out.new_line.Dedent();
|
|
1891
|
+
out.out += '}';
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
template <typename Input>
|
|
1896
|
+
static void Append(const Input& input, ByteSink& out) {
|
|
1897
|
+
using T = typename Input::value_type;
|
|
1898
|
+
AppendArrayPrefix(input.size(), out);
|
|
1899
|
+
for (const T& item : input) {
|
|
1900
|
+
TypeAdapter<T>::Append(item, out);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
template <typename Out>
|
|
1905
|
+
static void Parse(JsonTokenizer& tokenizer, Out& out) {
|
|
1906
|
+
switch (tokenizer.state().token_type) {
|
|
1907
|
+
case JsonTokenType::kLeftSquareBracket:
|
|
1908
|
+
break;
|
|
1909
|
+
case JsonTokenType::kZero:
|
|
1910
|
+
tokenizer.Next();
|
|
1911
|
+
return;
|
|
1912
|
+
default:
|
|
1913
|
+
tokenizer.mutable_state().PushErrorAtPosition("'['");
|
|
1914
|
+
}
|
|
1915
|
+
JsonArrayReader array_reader(&tokenizer);
|
|
1916
|
+
while (array_reader.NextElement()) {
|
|
1917
|
+
ParseAndPush(tokenizer, out);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
template <typename Out>
|
|
1922
|
+
static void Parse(ByteSource& source, Out& out) {
|
|
1923
|
+
uint32_t length = 0;
|
|
1924
|
+
ParseArrayPrefix(source, length);
|
|
1925
|
+
if (source.num_bytes_left() < length) {
|
|
1926
|
+
return source.RaiseError();
|
|
1927
|
+
};
|
|
1928
|
+
out.reserve(length);
|
|
1929
|
+
for (size_t i = 0; i < length; ++i) {
|
|
1930
|
+
if (source.error) return;
|
|
1931
|
+
ParseAndPush(source, out);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
template <typename T>
|
|
1936
|
+
static skir::reflection::Type GetType(skir_type<std::vector<T>>) {
|
|
1937
|
+
return skir::reflection::ArrayType{skir_internal::GetType<T>()};
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
template <typename T, typename GetKey>
|
|
1941
|
+
static skir::reflection::Type GetType(
|
|
1942
|
+
skir_type<skir::keyed_items<T, GetKey>>) {
|
|
1943
|
+
std::vector<std::string> key_chain;
|
|
1944
|
+
MakeKeyChain<GetKey>(key_chain);
|
|
1945
|
+
return skir::reflection::ArrayType{skir_internal::GetType<T>(),
|
|
1946
|
+
absl::StrJoin(key_chain, ".")};
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
template <typename T>
|
|
1950
|
+
static void RegisterRecords(skir_type<T>,
|
|
1951
|
+
skir::reflection::RecordRegistry& registry) {
|
|
1952
|
+
skir_internal::RegisterRecords<typename T::value_type>(registry);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
static constexpr bool IsStruct() { return false; }
|
|
1956
|
+
static constexpr bool IsEnum() { return false; }
|
|
1957
|
+
|
|
1958
|
+
private:
|
|
1959
|
+
template <typename Source>
|
|
1960
|
+
static void ParseAndPush(Source& source, std::vector<bool>& out) {
|
|
1961
|
+
bool item{};
|
|
1962
|
+
BoolAdapter::Parse(source, item);
|
|
1963
|
+
out.push_back(item);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
template <typename Source, typename T>
|
|
1967
|
+
static void ParseAndPush(Source& source, std::vector<T>& out) {
|
|
1968
|
+
T& item = out.emplace_back();
|
|
1969
|
+
TypeAdapter<T>::Parse(source, item);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
template <typename Source, typename T, typename GetKey>
|
|
1973
|
+
static void ParseAndPush(Source& source, skir::keyed_items<T, GetKey>& out) {
|
|
1974
|
+
T item{};
|
|
1975
|
+
TypeAdapter<T>::Parse(source, item);
|
|
1976
|
+
out.push_back(std::move(item));
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1979
|
+
|
|
1980
|
+
template <typename T>
|
|
1981
|
+
inline ArrayAdapter GetAdapter(skir_type<std::vector<T>>);
|
|
1982
|
+
|
|
1983
|
+
template <typename T, typename GetKey>
|
|
1984
|
+
inline ArrayAdapter GetAdapter(skir_type<skir::keyed_items<T, GetKey>>);
|
|
1985
|
+
|
|
1986
|
+
struct RecAdapter {
|
|
1987
|
+
template <typename T>
|
|
1988
|
+
static bool IsDefault(const skir::rec<T>& input) {
|
|
1989
|
+
return input.value_ == nullptr || TypeAdapter<T>::IsDefault(*input);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
template <typename T>
|
|
1993
|
+
static void Append(const skir::rec<T>& input, DenseJson& out) {
|
|
1994
|
+
if (input.value_ == nullptr) {
|
|
1995
|
+
out.out += {'[', ']'};
|
|
1996
|
+
} else {
|
|
1997
|
+
TypeAdapter<T>::Append(*input, out);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
template <typename T>
|
|
2002
|
+
static void Append(const skir::rec<T>& input, ReadableJson& out) {
|
|
2003
|
+
if (input.value_ == nullptr) {
|
|
2004
|
+
out.out += {'{', '}'};
|
|
2005
|
+
} else {
|
|
2006
|
+
TypeAdapter<T>::Append(*input, out);
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
template <typename T>
|
|
2011
|
+
static void Append(const skir::rec<T>& input, DebugString& out) {
|
|
2012
|
+
if (input.value_ == nullptr) {
|
|
2013
|
+
out.out += {'{', '}'};
|
|
2014
|
+
} else {
|
|
2015
|
+
TypeAdapter<T>::Append(*input, out);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
template <typename T>
|
|
2020
|
+
static void Append(const skir::rec<T>& input, ByteSink& out) {
|
|
2021
|
+
if (input.value_ == nullptr) {
|
|
2022
|
+
out.Push(246);
|
|
2023
|
+
} else {
|
|
2024
|
+
TypeAdapter<T>::Append(*input, out);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
template <typename T>
|
|
2029
|
+
static void Parse(JsonTokenizer& tokenizer, skir::rec<T>& out) {
|
|
2030
|
+
TypeAdapter<T>::Parse(tokenizer, *out);
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
template <typename T>
|
|
2034
|
+
static void Parse(ByteSource& source, skir::rec<T>& out) {
|
|
2035
|
+
return TypeAdapter<T>::Parse(source, *out);
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
template <typename T>
|
|
2039
|
+
static skir::reflection::Type GetType(skir_type<skir::rec<T>>) {
|
|
2040
|
+
return skir_internal::GetType<T>();
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
template <typename T>
|
|
2044
|
+
static void RegisterRecords(skir_type<skir::rec<T>>,
|
|
2045
|
+
skir::reflection::RecordRegistry& registry) {
|
|
2046
|
+
skir_internal::RegisterRecords<T>(registry);
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
static constexpr bool IsStruct() { return false; }
|
|
2050
|
+
static constexpr bool IsEnum() { return false; }
|
|
2051
|
+
};
|
|
2052
|
+
|
|
2053
|
+
template <typename T>
|
|
2054
|
+
inline RecAdapter GetAdapter(skir_type<skir::rec<T>>);
|
|
2055
|
+
|
|
2056
|
+
class JsonObjectWriter {
|
|
2057
|
+
public:
|
|
2058
|
+
JsonObjectWriter(ReadableJson* absl_nonnull out) : out_(*out) {}
|
|
2059
|
+
|
|
2060
|
+
~JsonObjectWriter() {
|
|
2061
|
+
if (has_content_) {
|
|
2062
|
+
out_.out += out_.new_line.Dedent();
|
|
2063
|
+
out_.out += '}';
|
|
2064
|
+
} else {
|
|
2065
|
+
out_.out += {'{', '}'};
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
template <typename T>
|
|
2070
|
+
JsonObjectWriter& Write(const char* absl_nonnull field_name, const T& value) {
|
|
2071
|
+
if (!TypeAdapter<T>::IsDefault(value)) {
|
|
2072
|
+
WriteEvenIfDefault(field_name, value);
|
|
2073
|
+
}
|
|
2074
|
+
return *this;
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
template <typename T>
|
|
2078
|
+
JsonObjectWriter& WriteEvenIfDefault(const char* absl_nonnull field_name,
|
|
2079
|
+
const T& value) {
|
|
2080
|
+
struct value_writer {
|
|
2081
|
+
const T& value_;
|
|
2082
|
+
|
|
2083
|
+
void operator()(ReadableJson& out) const {
|
|
2084
|
+
TypeAdapter<T>::Append(value_, out);
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
return WriteImpl(field_name, value_writer{value});
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
JsonObjectWriter& Write(const char* absl_nonnull field_name,
|
|
2091
|
+
const ReadableJson& value) {
|
|
2092
|
+
struct value_writer {
|
|
2093
|
+
const ReadableJson& value_;
|
|
2094
|
+
|
|
2095
|
+
void operator()(ReadableJson& out) const {
|
|
2096
|
+
out.out += absl::StrReplaceAll(value_.out, {{"\n", *out.new_line}});
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
return WriteImpl(field_name, value_writer{value});
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
template <typename value_writer_t>
|
|
2103
|
+
JsonObjectWriter& WriteImpl(const char* absl_nonnull field_name,
|
|
2104
|
+
value_writer_t value_writer) {
|
|
2105
|
+
if (has_content_) {
|
|
2106
|
+
out_.out += ',';
|
|
2107
|
+
out_.out += *out_.new_line;
|
|
2108
|
+
} else {
|
|
2109
|
+
out_.out += "{";
|
|
2110
|
+
out_.out += out_.new_line.Indent();
|
|
2111
|
+
has_content_ = true;
|
|
2112
|
+
}
|
|
2113
|
+
out_.out += '"';
|
|
2114
|
+
out_.out += field_name;
|
|
2115
|
+
out_.out += "\": ";
|
|
2116
|
+
value_writer(out_);
|
|
2117
|
+
return *this;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
private:
|
|
2121
|
+
ReadableJson& out_;
|
|
2122
|
+
bool has_content_ = false;
|
|
2123
|
+
};
|
|
2124
|
+
|
|
2125
|
+
class StructJsonObjectParserImpl {
|
|
2126
|
+
public:
|
|
2127
|
+
template <typename T, typename field_value>
|
|
2128
|
+
void AddField(const std::string& name,
|
|
2129
|
+
field_value T::* absl_nonnull data_member) {
|
|
2130
|
+
fields_[name] = std::make_unique<FieldImpl<T, field_value>>(data_member);
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
void Parse(JsonTokenizer& tokenizer, void* absl_nonnull out) const;
|
|
2134
|
+
|
|
2135
|
+
private:
|
|
2136
|
+
struct Field {
|
|
2137
|
+
virtual ~Field() = default;
|
|
2138
|
+
virtual void Parse(JsonTokenizer& tokenizer,
|
|
2139
|
+
void* absl_nonnull out) const = 0;
|
|
2140
|
+
};
|
|
2141
|
+
absl::flat_hash_map<std::string, std::unique_ptr<Field>> fields_;
|
|
2142
|
+
|
|
2143
|
+
template <typename T, typename field_value>
|
|
2144
|
+
struct FieldImpl : public Field {
|
|
2145
|
+
FieldImpl(field_value T::* absl_nonnull data_member)
|
|
2146
|
+
: data_member_(data_member) {}
|
|
2147
|
+
void Parse(JsonTokenizer& tokenizer,
|
|
2148
|
+
void* absl_nonnull out) const override {
|
|
2149
|
+
::skir_internal::Parse(tokenizer, static_cast<T*>(out)->*data_member_);
|
|
2150
|
+
}
|
|
2151
|
+
field_value T::* absl_nonnull const data_member_;
|
|
2152
|
+
};
|
|
2153
|
+
};
|
|
2154
|
+
|
|
2155
|
+
template <typename T>
|
|
2156
|
+
class StructJsonObjectParser {
|
|
2157
|
+
public:
|
|
2158
|
+
template <typename field_value>
|
|
2159
|
+
StructJsonObjectParser* absl_nonnull
|
|
2160
|
+
AddField(const std::string& name, field_value T::* absl_nonnull data_member) {
|
|
2161
|
+
impl_.AddField<T>(name, data_member);
|
|
2162
|
+
return this;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
void Parse(JsonTokenizer& tokenizer, T& out) const {
|
|
2166
|
+
impl_.Parse(tokenizer, &out);
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
private:
|
|
2170
|
+
StructJsonObjectParserImpl impl_;
|
|
2171
|
+
};
|
|
2172
|
+
|
|
2173
|
+
class EnumJsonObjectParserImpl {
|
|
2174
|
+
public:
|
|
2175
|
+
template <typename T, typename WrapperType>
|
|
2176
|
+
void AddVariant(const std::string& name) {
|
|
2177
|
+
variants_[name] = std::make_unique<VariantImpl<T, WrapperType>>();
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
template <typename T, typename ValueType>
|
|
2181
|
+
void AddVariantAsVariant(const std::string& name) {
|
|
2182
|
+
variants_[name] = std::make_unique<VariantAsVariantImpl<T, ValueType>>();
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
void Parse(JsonTokenizer& tokenizer, void* absl_nonnull out) const;
|
|
2186
|
+
|
|
2187
|
+
private:
|
|
2188
|
+
struct Variant {
|
|
2189
|
+
virtual ~Variant() = default;
|
|
2190
|
+
virtual void Parse(JsonTokenizer& tokenizer,
|
|
2191
|
+
void* absl_nonnull out) const = 0;
|
|
2192
|
+
};
|
|
2193
|
+
absl::flat_hash_map<std::string, std::unique_ptr<Variant>> variants_;
|
|
2194
|
+
|
|
2195
|
+
template <typename T, typename WrapperType>
|
|
2196
|
+
struct VariantImpl : public Variant {
|
|
2197
|
+
void Parse(JsonTokenizer& tokenizer,
|
|
2198
|
+
void* absl_nonnull out) const override {
|
|
2199
|
+
WrapperType wrapper;
|
|
2200
|
+
::skir_internal::Parse(tokenizer, wrapper.value);
|
|
2201
|
+
*static_cast<T*>(out) = std::move(wrapper);
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
|
|
2205
|
+
template <typename T, typename ValueType>
|
|
2206
|
+
struct VariantAsVariantImpl : public Variant {
|
|
2207
|
+
void Parse(JsonTokenizer& tokenizer,
|
|
2208
|
+
void* absl_nonnull out) const override {
|
|
2209
|
+
ValueType value;
|
|
2210
|
+
::skir_internal::Parse(tokenizer, value);
|
|
2211
|
+
*static_cast<T*>(out) = std::move(value);
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
2214
|
+
};
|
|
2215
|
+
|
|
2216
|
+
template <typename T>
|
|
2217
|
+
class EnumJsonObjectParser {
|
|
2218
|
+
public:
|
|
2219
|
+
template <typename WrapperType>
|
|
2220
|
+
EnumJsonObjectParser* absl_nonnull AddVariant(const std::string& name) {
|
|
2221
|
+
impl_.AddVariant<T, WrapperType>(name);
|
|
2222
|
+
return this;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
template <typename ValueType>
|
|
2226
|
+
EnumJsonObjectParser* absl_nonnull
|
|
2227
|
+
AddVariantAsVariant(const std::string& name) {
|
|
2228
|
+
impl_.AddVariantAsVariant<T, ValueType>(name);
|
|
2229
|
+
return this;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
void Parse(JsonTokenizer& tokenizer, T& out) const {
|
|
2233
|
+
impl_.Parse(tokenizer, &out);
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
private:
|
|
2237
|
+
EnumJsonObjectParserImpl impl_;
|
|
2238
|
+
};
|
|
2239
|
+
|
|
2240
|
+
class EnumJsonArrayParser {
|
|
2241
|
+
public:
|
|
2242
|
+
EnumJsonArrayParser(JsonTokenizer* absl_nonnull tokenizer);
|
|
2243
|
+
|
|
2244
|
+
int ReadNumber();
|
|
2245
|
+
void Finish();
|
|
2246
|
+
|
|
2247
|
+
private:
|
|
2248
|
+
JsonTokenizer& tokenizer_;
|
|
2249
|
+
};
|
|
2250
|
+
|
|
2251
|
+
class DebugObjectWriter {
|
|
2252
|
+
public:
|
|
2253
|
+
DebugObjectWriter(DebugString* absl_nonnull out) : out_(*out) {}
|
|
2254
|
+
|
|
2255
|
+
~DebugObjectWriter() {
|
|
2256
|
+
if (has_content_) {
|
|
2257
|
+
out_.out += out_.new_line.Dedent();
|
|
2258
|
+
out_.out += '}';
|
|
2259
|
+
} else {
|
|
2260
|
+
out_.out += {'{', '}'};
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
template <typename T>
|
|
2265
|
+
DebugObjectWriter& Write(const char* absl_nonnull field_name,
|
|
2266
|
+
const T& value) {
|
|
2267
|
+
if (!TypeAdapter<T>::IsDefault(value)) {
|
|
2268
|
+
if (has_content_) {
|
|
2269
|
+
out_.out += *out_.new_line;
|
|
2270
|
+
} else {
|
|
2271
|
+
out_.out += "{";
|
|
2272
|
+
out_.out += out_.new_line.Indent();
|
|
2273
|
+
has_content_ = true;
|
|
2274
|
+
}
|
|
2275
|
+
out_.out += '.';
|
|
2276
|
+
out_.out += field_name;
|
|
2277
|
+
out_.out += ": ";
|
|
2278
|
+
TypeAdapter<T>::Append(value, out_);
|
|
2279
|
+
out_.out += ',';
|
|
2280
|
+
}
|
|
2281
|
+
return *this;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
private:
|
|
2285
|
+
DebugString& out_;
|
|
2286
|
+
bool has_content_ = false;
|
|
2287
|
+
};
|
|
2288
|
+
|
|
2289
|
+
std::pair<bool, int32_t> ParseEnumPrefix(ByteSource& source);
|
|
2290
|
+
|
|
2291
|
+
enum class UnrecognizedFormat {
|
|
2292
|
+
kUnknown,
|
|
2293
|
+
kDenseJson,
|
|
2294
|
+
kBytes,
|
|
2295
|
+
};
|
|
2296
|
+
|
|
2297
|
+
class UnrecognizedValues {
|
|
2298
|
+
public:
|
|
2299
|
+
void ParseFrom(JsonTokenizer& tokenizer);
|
|
2300
|
+
void ParseFrom(ByteSource& source);
|
|
2301
|
+
void AppendTo(DenseJson& out) const;
|
|
2302
|
+
void AppendTo(ByteSink& out) const;
|
|
2303
|
+
|
|
2304
|
+
private:
|
|
2305
|
+
ByteSink bytes_;
|
|
2306
|
+
std::vector<uint32_t> array_lengths_;
|
|
2307
|
+
};
|
|
2308
|
+
|
|
2309
|
+
struct UnrecognizedFieldsData {
|
|
2310
|
+
UnrecognizedFormat format = UnrecognizedFormat::kUnknown;
|
|
2311
|
+
uint32_t array_len = 0;
|
|
2312
|
+
UnrecognizedValues values;
|
|
2313
|
+
};
|
|
2314
|
+
|
|
2315
|
+
template <typename Adapter>
|
|
2316
|
+
struct UnrecognizedFields {
|
|
2317
|
+
private:
|
|
2318
|
+
std::shared_ptr<UnrecognizedFieldsData> data;
|
|
2319
|
+
friend Adapter;
|
|
2320
|
+
};
|
|
2321
|
+
|
|
2322
|
+
struct UnrecognizedVariant {
|
|
2323
|
+
UnrecognizedFormat format = UnrecognizedFormat::kUnknown;
|
|
2324
|
+
int32_t number = 0;
|
|
2325
|
+
// Null if just a number with no value.
|
|
2326
|
+
std::shared_ptr<UnrecognizedValues> value;
|
|
2327
|
+
|
|
2328
|
+
UnrecognizedValues& emplace_value() {
|
|
2329
|
+
return *(value = std::make_shared<UnrecognizedValues>());
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
|
|
2333
|
+
void AppendUnrecognizedVariant(const UnrecognizedVariant* absl_nullable input,
|
|
2334
|
+
DenseJson& out);
|
|
2335
|
+
void AppendUnrecognizedVariant(const UnrecognizedVariant* absl_nullable input,
|
|
2336
|
+
ByteSink& out);
|
|
2337
|
+
|
|
2338
|
+
void ParseUnrecognizedFields(JsonArrayReader& array_reader, size_t num_slots,
|
|
2339
|
+
size_t num_slots_incl_removed,
|
|
2340
|
+
std::shared_ptr<UnrecognizedFieldsData>& out);
|
|
2341
|
+
|
|
2342
|
+
void ParseUnrecognizedFields(ByteSource& source, size_t array_len,
|
|
2343
|
+
size_t num_slots, size_t num_slots_incl_removed,
|
|
2344
|
+
std::shared_ptr<UnrecognizedFieldsData>& out);
|
|
2345
|
+
|
|
2346
|
+
template <typename HttplibHeaders>
|
|
2347
|
+
void SkirToHttplibHeaders(const skir::service::HttpHeaders& input,
|
|
2348
|
+
HttplibHeaders& out) {
|
|
2349
|
+
for (const auto& [name, values] : input.map()) {
|
|
2350
|
+
for (const absl::string_view value : values) {
|
|
2351
|
+
out.insert({std::string(name), std::string(value)});
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
template <typename HttplibHeaders>
|
|
2357
|
+
skir::service::HttpHeaders HttplibToSkirHeaders(const HttplibHeaders& input) {
|
|
2358
|
+
skir::service::HttpHeaders result;
|
|
2359
|
+
for (const auto& [name, value] : input) {
|
|
2360
|
+
result.Insert(name, value);
|
|
2361
|
+
}
|
|
2362
|
+
return result;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
template <typename MethodsTuple, std::size_t... Indices>
|
|
2366
|
+
constexpr bool unique_method_numbers_impl(std::index_sequence<Indices...>) {
|
|
2367
|
+
constexpr std::array<int, sizeof...(Indices)> numbers = {
|
|
2368
|
+
std::get<Indices>(MethodsTuple()).kNumber...};
|
|
2369
|
+
for (std::size_t i = 0; i < sizeof...(Indices); ++i) {
|
|
2370
|
+
for (std::size_t j = i + 1; j < sizeof...(Indices); ++j) {
|
|
2371
|
+
if (numbers[i] == numbers[j]) {
|
|
2372
|
+
return false;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
return true;
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
template <typename MethodsTuple>
|
|
2380
|
+
constexpr bool unique_method_numbers() {
|
|
2381
|
+
return unique_method_numbers_impl<MethodsTuple>(
|
|
2382
|
+
std::make_index_sequence<std::tuple_size_v<MethodsTuple>>{});
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
template <typename MethodsTuple>
|
|
2386
|
+
void assert_unique_method_numbers() {
|
|
2387
|
+
static_assert(unique_method_numbers<MethodsTuple>(),
|
|
2388
|
+
"Method numbers are not unique");
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
} // namespace skir_internal
|
|
2392
|
+
|
|
2393
|
+
namespace skir {
|
|
2394
|
+
|
|
2395
|
+
// Deserializes a skir value.
|
|
2396
|
+
// The input string can either be:
|
|
2397
|
+
// - the JSON returned by skir::ToDenseJson or skir::ToReadableJson
|
|
2398
|
+
// - the bytes returned by skir::ToBytes
|
|
2399
|
+
template <typename T>
|
|
2400
|
+
absl::StatusOr<T> Parse(absl::string_view bytes_or_json,
|
|
2401
|
+
UnrecognizedValuesPolicy unrecognized_values =
|
|
2402
|
+
UnrecognizedValuesPolicy::kDrop) {
|
|
2403
|
+
T result{};
|
|
2404
|
+
if (bytes_or_json.length() >= 4 && bytes_or_json[0] == 's' &&
|
|
2405
|
+
bytes_or_json[1] == 'k' && bytes_or_json[2] == 'i' &&
|
|
2406
|
+
bytes_or_json[3] == 'r') {
|
|
2407
|
+
bytes_or_json = bytes_or_json.substr(4);
|
|
2408
|
+
skir_internal::ByteSource byte_source(bytes_or_json.data(),
|
|
2409
|
+
bytes_or_json.length());
|
|
2410
|
+
byte_source.keep_unrecognized_values =
|
|
2411
|
+
unrecognized_values == UnrecognizedValuesPolicy::kKeep;
|
|
2412
|
+
skir_internal::Parse(byte_source, result);
|
|
2413
|
+
if (byte_source.error || byte_source.pos < byte_source.end) {
|
|
2414
|
+
return absl::UnknownError("error while decoding skir value from bytes");
|
|
2415
|
+
}
|
|
2416
|
+
} else {
|
|
2417
|
+
skir_internal::JsonTokenizer tokenizer(
|
|
2418
|
+
bytes_or_json.begin(), bytes_or_json.end(), unrecognized_values);
|
|
2419
|
+
tokenizer.Next();
|
|
2420
|
+
skir_internal::Parse(tokenizer, result);
|
|
2421
|
+
if (tokenizer.state().token_type != skir_internal::JsonTokenType::kStrEnd) {
|
|
2422
|
+
tokenizer.mutable_state().PushUnexpectedTokenError("end");
|
|
2423
|
+
}
|
|
2424
|
+
const absl::Status status = tokenizer.state().status;
|
|
2425
|
+
if (!status.ok()) return status;
|
|
2426
|
+
}
|
|
2427
|
+
return result;
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
// Serializes the given value to dense JSON format.
|
|
2431
|
+
template <typename T>
|
|
2432
|
+
std::string ToDenseJson(const T& input) {
|
|
2433
|
+
static_assert(!std::is_pointer<T>::value,
|
|
2434
|
+
"Can't pass a pointer to ToDenseJson");
|
|
2435
|
+
skir_internal::DenseJson dense_json;
|
|
2436
|
+
Append(input, dense_json);
|
|
2437
|
+
return std::move(dense_json).out;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
inline std::string ToDenseJson(const char* absl_nonnull input) {
|
|
2441
|
+
return ToDenseJson(std::string(input));
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
// Serializes the given value to readable JSON format.
|
|
2445
|
+
template <typename T>
|
|
2446
|
+
std::string ToReadableJson(const T& input) {
|
|
2447
|
+
static_assert(!std::is_pointer<T>::value,
|
|
2448
|
+
"Can't pass a pointer to ToReadableJson");
|
|
2449
|
+
skir_internal::ReadableJson readable_json;
|
|
2450
|
+
Append(input, readable_json);
|
|
2451
|
+
return std::move(readable_json).out;
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
inline std::string ToReadableJson(const char* absl_nonnull input) {
|
|
2455
|
+
return ToReadableJson(std::string(input));
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
// Serializes the given value to binary format.
|
|
2459
|
+
template <typename T>
|
|
2460
|
+
ByteString ToBytes(const T& input) {
|
|
2461
|
+
static_assert(!std::is_pointer<T>::value, "Can't pass a pointer to ToBytes");
|
|
2462
|
+
skir_internal::ByteSink byte_sink;
|
|
2463
|
+
byte_sink.Push('s', 'k', 'i', 'r');
|
|
2464
|
+
Append(input, byte_sink);
|
|
2465
|
+
return std::move(byte_sink).ToByteString();
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
inline ByteString ToBytes(const char* absl_nonnull input) {
|
|
2469
|
+
return ToBytes(std::string(input));
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// Minimum absl::Time encodable as a skir timestamp.
|
|
2473
|
+
// Equal to 100M days before the Unix EPOCH.
|
|
2474
|
+
constexpr absl::Time kMinEncodedTimestamp =
|
|
2475
|
+
absl::FromUnixMillis(-8640000000000000);
|
|
2476
|
+
// Maximum absl::Time encodable as a skir timestamp.
|
|
2477
|
+
// Equal to 100M days before the Unix EPOCH.
|
|
2478
|
+
constexpr absl::Time kMaxEncodedTimestamp =
|
|
2479
|
+
absl::FromUnixMillis(8640000000000000);
|
|
2480
|
+
|
|
2481
|
+
template <typename H, typename T>
|
|
2482
|
+
H AbslHashValue(H h, const rec<T>& rec) {
|
|
2483
|
+
if (::skir_internal::RecAdapter::IsDefault(rec)) {
|
|
2484
|
+
return H::combine(std::move(h), -6387689);
|
|
2485
|
+
} else {
|
|
2486
|
+
return H::combine(std::move(h), *rec);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
namespace reflection {
|
|
2491
|
+
|
|
2492
|
+
template <typename T>
|
|
2493
|
+
const TypeDescriptor& GetTypeDescriptor() {
|
|
2494
|
+
static const TypeDescriptor* result = []() -> const TypeDescriptor* {
|
|
2495
|
+
RecordRegistry registry;
|
|
2496
|
+
skir_internal::RegisterRecords<T>(registry);
|
|
2497
|
+
return new TypeDescriptor{skir_internal::GetType<T>(), std::move(registry)};
|
|
2498
|
+
}();
|
|
2499
|
+
return *result;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
template <typename T>
|
|
2503
|
+
constexpr bool IsStruct() {
|
|
2504
|
+
return skir_internal::TypeAdapter<T>::IsStruct();
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
template <typename T>
|
|
2508
|
+
constexpr bool IsEnum() {
|
|
2509
|
+
return skir_internal::TypeAdapter<T>::IsEnum();
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
template <typename T>
|
|
2513
|
+
constexpr bool IsRecord() {
|
|
2514
|
+
return IsStruct<T>() || IsEnum<T>();
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// Calls f(field) for each field in the skir-generated datatype.
|
|
2518
|
+
// The type of the single argument passed to f is struct_field.
|
|
2519
|
+
template <typename Record, typename F>
|
|
2520
|
+
void ForEachField(F&& f) {
|
|
2521
|
+
static_assert(IsStruct<Record>());
|
|
2522
|
+
std::apply(
|
|
2523
|
+
[&f](auto&&... x) {
|
|
2524
|
+
(static_cast<void>(f(std::forward<decltype(x)>(x))), ...);
|
|
2525
|
+
},
|
|
2526
|
+
typename skir_internal::TypeAdapter<Record>::fields_tuple());
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
// Calls f(variant) for each variant in the skir-generated datatype.
|
|
2530
|
+
// The type of the single argument passed to f is either enum_const_variant
|
|
2531
|
+
// or enum_wrapper_variant.
|
|
2532
|
+
template <typename Record, typename F>
|
|
2533
|
+
void ForEachVariant(F&& f) {
|
|
2534
|
+
static_assert(IsEnum<Record>());
|
|
2535
|
+
std::apply(
|
|
2536
|
+
[&f](auto&&... x) {
|
|
2537
|
+
(static_cast<void>(f(std::forward<decltype(x)>(x))), ...);
|
|
2538
|
+
},
|
|
2539
|
+
typename skir_internal::TypeAdapter<Record>::variants_tuple());
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
} // namespace reflection
|
|
2543
|
+
} // namespace skir
|
|
2544
|
+
|
|
2545
|
+
namespace skir_internal {
|
|
2546
|
+
|
|
2547
|
+
struct RequestBody {
|
|
2548
|
+
std::string method_name;
|
|
2549
|
+
absl::optional<int64_t> method_number;
|
|
2550
|
+
bool readable = true;
|
|
2551
|
+
absl::string_view request_data;
|
|
2552
|
+
|
|
2553
|
+
absl::Status Parse(absl::string_view request_body);
|
|
2554
|
+
};
|
|
2555
|
+
|
|
2556
|
+
struct MethodDescriptor {
|
|
2557
|
+
absl::string_view name;
|
|
2558
|
+
int64_t number = 0;
|
|
2559
|
+
ReadableJson request_descriptor_json;
|
|
2560
|
+
ReadableJson response_descriptor_json;
|
|
2561
|
+
std::string doc;
|
|
2562
|
+
};
|
|
2563
|
+
|
|
2564
|
+
template <typename Method>
|
|
2565
|
+
MethodDescriptor MakeMethodDescriptor(Method method) {
|
|
2566
|
+
MethodDescriptor result;
|
|
2567
|
+
result.name = Method::kMethodName;
|
|
2568
|
+
result.number = Method::kNumber;
|
|
2569
|
+
result.request_descriptor_json.out =
|
|
2570
|
+
skir::reflection::GetTypeDescriptor<typename Method::request_type>()
|
|
2571
|
+
.AsJson();
|
|
2572
|
+
result.response_descriptor_json.out =
|
|
2573
|
+
skir::reflection::GetTypeDescriptor<typename Method::response_type>()
|
|
2574
|
+
.AsJson();
|
|
2575
|
+
result.doc = Method::kDoc;
|
|
2576
|
+
return result;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
struct MethodList {
|
|
2580
|
+
std::vector<MethodDescriptor> methods;
|
|
2581
|
+
};
|
|
2582
|
+
|
|
2583
|
+
struct MethodDescriptorAdapter {
|
|
2584
|
+
static bool IsDefault(const MethodDescriptor& input) { return false; }
|
|
2585
|
+
static void Append(const MethodDescriptor& input, ReadableJson& out);
|
|
2586
|
+
};
|
|
2587
|
+
|
|
2588
|
+
struct MethodListAdapter {
|
|
2589
|
+
static bool IsDefault(const MethodList& input) { return false; }
|
|
2590
|
+
static void Append(const MethodList& input, ReadableJson& out);
|
|
2591
|
+
};
|
|
2592
|
+
|
|
2593
|
+
inline MethodDescriptorAdapter GetAdapter(skir_type<MethodDescriptor>);
|
|
2594
|
+
inline MethodListAdapter GetAdapter(skir_type<MethodList>);
|
|
2595
|
+
|
|
2596
|
+
constexpr absl::string_view kRestudioHtml = R"html(<!DOCTYPE html>
|
|
2597
|
+
|
|
2598
|
+
<html>
|
|
2599
|
+
<head>
|
|
2600
|
+
<meta charset="utf-8" />
|
|
2601
|
+
<title>RESTudio</title>
|
|
2602
|
+
<script src="https://cdn.jsdelivr.net/npm/restudio/dist/restudio-standalone.js"></script>
|
|
2603
|
+
</head>
|
|
2604
|
+
<body style="margin: 0; padding: 0;">
|
|
2605
|
+
<restudio-app></restudio-app>
|
|
2606
|
+
</body>
|
|
2607
|
+
</html>
|
|
2608
|
+
)html";
|
|
2609
|
+
|
|
2610
|
+
template <typename ServiceImpl, typename RequestMeta, typename ResponseMeta>
|
|
2611
|
+
class HandleRequestOp {
|
|
2612
|
+
public:
|
|
2613
|
+
HandleRequestOp(ServiceImpl* absl_nonnull service_impl,
|
|
2614
|
+
absl::string_view request_body,
|
|
2615
|
+
skir::UnrecognizedValuesPolicy unrecognized_values,
|
|
2616
|
+
const RequestMeta* absl_nonnull request_meta,
|
|
2617
|
+
ResponseMeta* absl_nonnull response_meta)
|
|
2618
|
+
: service_impl_(*service_impl),
|
|
2619
|
+
request_body_(request_body),
|
|
2620
|
+
unrecognized_values_(unrecognized_values),
|
|
2621
|
+
request_meta_(*request_meta),
|
|
2622
|
+
response_meta_(*response_meta) {}
|
|
2623
|
+
|
|
2624
|
+
skir::service::RawResponse Run() {
|
|
2625
|
+
if (request_body_ == "" || request_body_ == "list") {
|
|
2626
|
+
MethodList method_list;
|
|
2627
|
+
std::apply(
|
|
2628
|
+
[&](auto... method) {
|
|
2629
|
+
(method_list.methods.push_back(MakeMethodDescriptor(method)), ...);
|
|
2630
|
+
},
|
|
2631
|
+
typename ServiceImpl::methods());
|
|
2632
|
+
ReadableJson json;
|
|
2633
|
+
MethodListAdapter::Append(method_list, json);
|
|
2634
|
+
return {
|
|
2635
|
+
json.out,
|
|
2636
|
+
skir::service::ResponseType::kOkJson,
|
|
2637
|
+
};
|
|
2638
|
+
} else if (request_body_ == "debug" || request_body_ == "restudio") {
|
|
2639
|
+
return {std::string(kRestudioHtml), skir::service::ResponseType::kOkHtml};
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
if (const absl::Status status = request_body_parsed_.Parse(request_body_);
|
|
2643
|
+
!status.ok()) {
|
|
2644
|
+
return {
|
|
2645
|
+
absl::StrCat("bad request: ", status.message()),
|
|
2646
|
+
skir::service::ResponseType::kBadRequest,
|
|
2647
|
+
};
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
std::apply(
|
|
2651
|
+
[&](auto... method) {
|
|
2652
|
+
(static_cast<void>(MaybeInvokeMethod(method)), ...);
|
|
2653
|
+
},
|
|
2654
|
+
typename ServiceImpl::methods());
|
|
2655
|
+
if (raw_response_.has_value()) {
|
|
2656
|
+
return std::move(*raw_response_);
|
|
2657
|
+
}
|
|
2658
|
+
return {
|
|
2659
|
+
absl::StrCat(
|
|
2660
|
+
"bad request: method not found: ", request_body_parsed_.method_name,
|
|
2661
|
+
"; number: ", request_body_parsed_.method_number.value_or(-1)),
|
|
2662
|
+
skir::service::ResponseType::kBadRequest};
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
private:
|
|
2666
|
+
ServiceImpl& service_impl_;
|
|
2667
|
+
const absl::string_view request_body_;
|
|
2668
|
+
const skir::UnrecognizedValuesPolicy unrecognized_values_;
|
|
2669
|
+
const RequestMeta& request_meta_;
|
|
2670
|
+
ResponseMeta& response_meta_;
|
|
2671
|
+
|
|
2672
|
+
RequestBody request_body_parsed_;
|
|
2673
|
+
|
|
2674
|
+
absl::optional<skir::service::RawResponse> raw_response_;
|
|
2675
|
+
|
|
2676
|
+
template <typename Method>
|
|
2677
|
+
void MaybeInvokeMethod(Method method) {
|
|
2678
|
+
using MethodType = decltype(method);
|
|
2679
|
+
using RequestType = typename MethodType::request_type;
|
|
2680
|
+
using ResponseType = typename MethodType::response_type;
|
|
2681
|
+
if (request_body_parsed_.method_number.has_value()) {
|
|
2682
|
+
if (MethodType::kNumber != *request_body_parsed_.method_number) return;
|
|
2683
|
+
} else {
|
|
2684
|
+
if (MethodType::kMethodName != request_body_parsed_.method_name) return;
|
|
2685
|
+
}
|
|
2686
|
+
if (raw_response_.has_value()) {
|
|
2687
|
+
// Should only happen if multiple methods have the same name and the
|
|
2688
|
+
// request does not specify the method number. We should probably return
|
|
2689
|
+
// an error in this case.
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2692
|
+
raw_response_.emplace();
|
|
2693
|
+
absl::StatusOr<RequestType> request = skir::Parse<RequestType>(
|
|
2694
|
+
request_body_parsed_.request_data, unrecognized_values_);
|
|
2695
|
+
if (!request.ok()) {
|
|
2696
|
+
raw_response_->data =
|
|
2697
|
+
absl::StrCat("bad request: ", request.status().message());
|
|
2698
|
+
raw_response_->type = skir::service::ResponseType::kBadRequest;
|
|
2699
|
+
return;
|
|
2700
|
+
}
|
|
2701
|
+
absl::StatusOr<ResponseType> output = service_impl_(
|
|
2702
|
+
method, std::move(*request), request_meta_, response_meta_);
|
|
2703
|
+
if (!output.ok()) {
|
|
2704
|
+
raw_response_->data =
|
|
2705
|
+
absl::StrCat("server error: ", output.status().message());
|
|
2706
|
+
raw_response_->type = skir::service::ResponseType::kServerError;
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
if (request_body_parsed_.readable) {
|
|
2710
|
+
raw_response_->data = skir::ToReadableJson(*output);
|
|
2711
|
+
raw_response_->type = skir::service::ResponseType::kOkJson;
|
|
2712
|
+
} else {
|
|
2713
|
+
raw_response_->data = skir::ToDenseJson(*output);
|
|
2714
|
+
raw_response_->type = skir::service::ResponseType::kOkJson;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
};
|
|
2718
|
+
|
|
2719
|
+
template <typename HttplibClientPtr>
|
|
2720
|
+
class HttplibClient : public skir::service::Client {
|
|
2721
|
+
public:
|
|
2722
|
+
HttplibClient(HttplibClientPtr client, std::string query_path)
|
|
2723
|
+
: client_(std::move(ABSL_DIE_IF_NULL(client))), query_path_(query_path) {}
|
|
2724
|
+
|
|
2725
|
+
absl::StatusOr<std::string> operator()(
|
|
2726
|
+
absl::string_view request_data,
|
|
2727
|
+
const skir::service::HttpHeaders& request_headers,
|
|
2728
|
+
skir::service::HttpHeaders& response_headers) const {
|
|
2729
|
+
auto headers =
|
|
2730
|
+
decltype(std::declval<HttplibClientPtr>()->Get("")->headers)();
|
|
2731
|
+
SkirToHttplibHeaders(request_headers, headers);
|
|
2732
|
+
auto result =
|
|
2733
|
+
client_->Post(query_path_, headers, request_data.data(),
|
|
2734
|
+
request_data.length(), "text/plain; charset=utf-8");
|
|
2735
|
+
if (result) {
|
|
2736
|
+
response_headers = HttplibToSkirHeaders(result->headers);
|
|
2737
|
+
const int status_code = result->status;
|
|
2738
|
+
if (200 <= status_code && status_code <= 299) {
|
|
2739
|
+
// OK status.
|
|
2740
|
+
return std::move(result->body);
|
|
2741
|
+
} else {
|
|
2742
|
+
const std::string content_type =
|
|
2743
|
+
result->get_header_value("Content-Type");
|
|
2744
|
+
const bool body_is_text =
|
|
2745
|
+
content_type == "text/plain" ||
|
|
2746
|
+
absl::StartsWith(content_type, "text/plain ") ||
|
|
2747
|
+
absl::StartsWith(content_type, "text/plain;");
|
|
2748
|
+
return absl::UnknownError(absl::StrCat(
|
|
2749
|
+
"HTTP response status ", status_code, body_is_text ? ": " : "",
|
|
2750
|
+
body_is_text ? result->body : ""));
|
|
2751
|
+
}
|
|
2752
|
+
} else {
|
|
2753
|
+
// HTTP error.
|
|
2754
|
+
response_headers = {};
|
|
2755
|
+
std::stringstream ss;
|
|
2756
|
+
ss << "HTTP error: " << result.error();
|
|
2757
|
+
return {absl::UnknownError(ss.str())};
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
private:
|
|
2762
|
+
const HttplibClientPtr client_;
|
|
2763
|
+
const std::string query_path_;
|
|
2764
|
+
};
|
|
2765
|
+
|
|
2766
|
+
} // namespace skir_internal
|
|
2767
|
+
|
|
2768
|
+
namespace skir {
|
|
2769
|
+
namespace service {
|
|
2770
|
+
|
|
2771
|
+
// On the server side, parses the content of a user request and invokes the
|
|
2772
|
+
// appropriate method on the given service implementation.
|
|
2773
|
+
//
|
|
2774
|
+
// ServiceImpl must satisfy the following requirements:
|
|
2775
|
+
// 1. It must have a public `methods` type alias which resolves to a tuple of
|
|
2776
|
+
// // method types.
|
|
2777
|
+
// 2. For each method, it must have a member function with this signature:
|
|
2778
|
+
// absl::StatusOr<typename Method::response_type> operator()(
|
|
2779
|
+
// Method method,
|
|
2780
|
+
// typename Method::request_type request,
|
|
2781
|
+
// const HttpHeaders& request_headers,
|
|
2782
|
+
// HttpHeaders& response_headers);
|
|
2783
|
+
//
|
|
2784
|
+
// For example:
|
|
2785
|
+
//
|
|
2786
|
+
// class MyServiceImpl {
|
|
2787
|
+
// public:
|
|
2788
|
+
// using methods = std::tuple<
|
|
2789
|
+
// skirout_methods::ListUsers,
|
|
2790
|
+
// skirout_methods::GetUser>;
|
|
2791
|
+
//
|
|
2792
|
+
// absl::StatusOr<skirout_methods::ListUsersResponse> operator()(
|
|
2793
|
+
// skirout_methods::ListUsers,
|
|
2794
|
+
// skirout_methods::ListUsersRequest request,
|
|
2795
|
+
// const HttpHeaders& request_headers,
|
|
2796
|
+
// HttpHeaders& response_headers) const {
|
|
2797
|
+
// ...
|
|
2798
|
+
// }
|
|
2799
|
+
//
|
|
2800
|
+
// absl::StatusOr<skirout_methods::GetUserResponse> operator()(
|
|
2801
|
+
// skirout_methods::GetUser,
|
|
2802
|
+
// skirout_methods::GetUserRequest request,
|
|
2803
|
+
// const HttpHeaders& request_headers,
|
|
2804
|
+
// HttpHeaders& response_headers) const {
|
|
2805
|
+
// ...
|
|
2806
|
+
// }
|
|
2807
|
+
// };
|
|
2808
|
+
//
|
|
2809
|
+
// If you are using cpp-httplib (https://github.com/yhirose/cpp-httplib) as
|
|
2810
|
+
// your server library, you don't need to call HandleRequest, you can simply
|
|
2811
|
+
// call InstallServiceOnHttplibServer. If you are using another server library,
|
|
2812
|
+
// call HandleRequest in the logic for installing a skir service on your
|
|
2813
|
+
// server.
|
|
2814
|
+
//
|
|
2815
|
+
// If the request is a GET request, pass in the decoded query string as the
|
|
2816
|
+
// request's body. The query string is the part of the URL after '?', and it can
|
|
2817
|
+
// be decoded with DecodeUrlQueryString.
|
|
2818
|
+
//
|
|
2819
|
+
// Pass in UnrecognizedValuesPolicy::kKeep if the request is guaranteed to come
|
|
2820
|
+
// from a trusted user.
|
|
2821
|
+
template <typename ServiceImpl>
|
|
2822
|
+
RawResponse HandleRequest(ServiceImpl& service_impl,
|
|
2823
|
+
absl::string_view request_body,
|
|
2824
|
+
const HttpHeaders& request_headers,
|
|
2825
|
+
HttpHeaders& response_headers,
|
|
2826
|
+
UnrecognizedValuesPolicy unrecognized_values =
|
|
2827
|
+
UnrecognizedValuesPolicy::kDrop) {
|
|
2828
|
+
skir_internal::assert_unique_method_numbers<typename ServiceImpl::methods>();
|
|
2829
|
+
return skir_internal::HandleRequestOp(&service_impl, request_body,
|
|
2830
|
+
unrecognized_values, &request_headers,
|
|
2831
|
+
&response_headers)
|
|
2832
|
+
.Run();
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
// Decodes the given query string encoded with Javascript's
|
|
2836
|
+
// encodeURIComponent functon.
|
|
2837
|
+
// For example: "foo%20%3F%3D%23" -> "foo ?=#"
|
|
2838
|
+
absl::StatusOr<std::string> DecodeUrlQueryString(
|
|
2839
|
+
absl::string_view encoded_query_string);
|
|
2840
|
+
|
|
2841
|
+
// Installs a skir service on the given httplib::Server at the given query
|
|
2842
|
+
// path. The httplib::Server type is referred to as a template parameter so as
|
|
2843
|
+
// not to make cpp-httplib a dependency of skir.
|
|
2844
|
+
//
|
|
2845
|
+
// ServiceImpl must satisfy the requirements outlined in the documentation for
|
|
2846
|
+
// HandleRequest.
|
|
2847
|
+
//
|
|
2848
|
+
// Pass in UnrecognizedValuesPolicy::kKeep if the request is guaranteed to come
|
|
2849
|
+
// from a trusted user.
|
|
2850
|
+
template <typename HttplibServer, typename ServiceImpl>
|
|
2851
|
+
void InstallServiceOnHttplibServer(
|
|
2852
|
+
HttplibServer& server, absl::string_view query_path,
|
|
2853
|
+
std::shared_ptr<ServiceImpl> service_impl,
|
|
2854
|
+
UnrecognizedValuesPolicy unrecognized_values =
|
|
2855
|
+
UnrecognizedValuesPolicy::kDrop) {
|
|
2856
|
+
ABSL_CHECK_NE(service_impl, nullptr);
|
|
2857
|
+
const typename HttplibServer::Handler handler = //
|
|
2858
|
+
[service_impl, unrecognized_values](const auto& req, auto& resp) {
|
|
2859
|
+
const HttpHeaders request_headers =
|
|
2860
|
+
skir_internal::HttplibToSkirHeaders(req.headers);
|
|
2861
|
+
HttpHeaders response_headers;
|
|
2862
|
+
absl::string_view request_body;
|
|
2863
|
+
std::string decoded_query_string;
|
|
2864
|
+
if (!req.body.empty()) {
|
|
2865
|
+
request_body = req.body;
|
|
2866
|
+
} else {
|
|
2867
|
+
const absl::string_view target = req.target;
|
|
2868
|
+
absl::string_view query_string;
|
|
2869
|
+
const size_t index_of_question_mark = target.find('?');
|
|
2870
|
+
if (index_of_question_mark != absl::string_view::npos) {
|
|
2871
|
+
query_string = target.substr(index_of_question_mark + 1);
|
|
2872
|
+
}
|
|
2873
|
+
decoded_query_string =
|
|
2874
|
+
DecodeUrlQueryString(query_string).value_or("");
|
|
2875
|
+
request_body = decoded_query_string;
|
|
2876
|
+
}
|
|
2877
|
+
RawResponse raw_response =
|
|
2878
|
+
HandleRequest(*service_impl, request_body, request_headers,
|
|
2879
|
+
response_headers, unrecognized_values);
|
|
2880
|
+
skir_internal::SkirToHttplibHeaders(response_headers, resp.headers);
|
|
2881
|
+
|
|
2882
|
+
resp.set_content(std::move(raw_response.data),
|
|
2883
|
+
std::string(raw_response.content_type()));
|
|
2884
|
+
resp.status = raw_response.status_code();
|
|
2885
|
+
};
|
|
2886
|
+
server.Get(std::string(query_path), handler);
|
|
2887
|
+
server.Post(std::string(query_path), handler);
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
// Invokes the given method on a remote server through an RPC.
|
|
2891
|
+
// Returns an error status if there was a network error or if the server
|
|
2892
|
+
// returned an error.
|
|
2893
|
+
template <typename Method>
|
|
2894
|
+
absl::StatusOr<typename Method::response_type> InvokeRemote(
|
|
2895
|
+
const Client& client, Method method,
|
|
2896
|
+
const typename Method::request_type& request,
|
|
2897
|
+
const HttpHeaders& request_headers = {},
|
|
2898
|
+
HttpHeaders* absl_nonnull response_headers = nullptr) {
|
|
2899
|
+
const std::string request_data = absl::StrCat(
|
|
2900
|
+
Method::kMethodName, ":", Method::kNumber, "::", ToDenseJson(request));
|
|
2901
|
+
HttpHeaders response_headers_tmp;
|
|
2902
|
+
absl::StatusOr<std::string> response_data =
|
|
2903
|
+
client(request_data, request_headers, response_headers_tmp);
|
|
2904
|
+
if (response_headers != nullptr) {
|
|
2905
|
+
*response_headers = std::move(response_headers_tmp);
|
|
2906
|
+
}
|
|
2907
|
+
if (!response_data.ok()) {
|
|
2908
|
+
return std::move(response_data).status();
|
|
2909
|
+
}
|
|
2910
|
+
return Parse<typename Method::response_type>(*response_data,
|
|
2911
|
+
UnrecognizedValuesPolicy::kKeep);
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2914
|
+
// Returns a client for sending RPCs to a skir service via the given
|
|
2915
|
+
// httplib::Client.
|
|
2916
|
+
// The httplib::Client type is referred to as a template parameter so as not to
|
|
2917
|
+
// make cpp-httplib a dependency of skir.
|
|
2918
|
+
//
|
|
2919
|
+
// If you are not using cpp-httplib, you can write your own Client
|
|
2920
|
+
// implementation.
|
|
2921
|
+
template <typename HttplibClient>
|
|
2922
|
+
std::unique_ptr<Client> MakeHttplibClient(HttplibClient* absl_nonnull client,
|
|
2923
|
+
absl::string_view query_path) {
|
|
2924
|
+
return std::make_unique<skir_internal::HttplibClient<HttplibClient*>>(
|
|
2925
|
+
client, std::string(query_path));
|
|
2926
|
+
};
|
|
2927
|
+
|
|
2928
|
+
// Returns a client for sending RPCs to a skir service via the given
|
|
2929
|
+
// httplib::Client.
|
|
2930
|
+
// The httplib::Client type is referred to as a template parameter so as not to
|
|
2931
|
+
// make cpp-httplib a dependency of skir.
|
|
2932
|
+
//
|
|
2933
|
+
// If you are not using cpp-httplib, you can write your own Client
|
|
2934
|
+
// implementation.
|
|
2935
|
+
template <typename HttplibClient>
|
|
2936
|
+
std::unique_ptr<Client> MakeHttplibClient(std::unique_ptr<HttplibClient> client,
|
|
2937
|
+
absl::string_view query_path) {
|
|
2938
|
+
return std::make_unique<
|
|
2939
|
+
skir_internal::HttplibClient<std::unique_ptr<HttplibClient>>>(
|
|
2940
|
+
std::move(client), std::string(query_path));
|
|
2941
|
+
};
|
|
2942
|
+
|
|
2943
|
+
} // namespace service
|
|
2944
|
+
} // namespace skir
|
|
2945
|
+
|
|
2946
|
+
#endif
|