DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
Etf.hpp
Go to the documentation of this file.
1/*
2 MIT License
3
4 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
5
6 Copyright 2022, 2023 Chris M. (RealTimeChris)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25*/
26/// Etf.hpp - Header for the erlpacking class.
27/// Nov 8, 2021
28/// https://discordcoreapi.com
29/// \file Etf.hpp
30#pragma once
31
33
34namespace discord_core_api {
35
36 namespace discord_core_internal {
37
38 /**
39 * \addtogroup discord_core_internal
40 * @{
41 */
42 template<typename return_type> DCA_INLINE return_type ntohsNew(return_type value) {
43 return static_cast<return_type>(((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8));
44 }
45
46 template<typename return_type> DCA_INLINE return_type ntohlNew(return_type value) {
47 return static_cast<return_type>(((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24));
48 }
49
50 template<typename return_type> DCA_INLINE return_type ntohllNew(return_type value) {
51 return static_cast<return_type>(((value & 0x00000000000000FFull) << 56) | ((value & 0x000000000000FF00ULL) << 40) | ((value & 0x0000000000FF0000ULL) << 24) |
52 ((value & 0x00000000FF000000ULL) << 8) | ((value & 0x000000FF00000000ULL) >> 8) | ((value & 0x0000FF0000000000ULL) >> 24) |
53 ((value & 0x00FF000000000000ULL) >> 40) | ((value & 0xFF00000000000000ULL) >> 56));
54 }
55
56 /// @brief Reverses the byte order of a value if needed, based on the endianness.
57 /// @tparam return_type the type of the value to reverse.
58 /// @param net the value to reverse.
59 /// @return the reversed value.
60 template<typename return_type> DCA_INLINE void reverseByteOrder(return_type& net) {
61 if constexpr (std::endian::native == std::endian::little) {
62 switch (sizeof(return_type)) {
63 case 2: {
64 net = ntohsNew(net);
65 return;
66 }
67 case 4: {
68 net = ntohlNew(net);
69 return;
70 }
71 case 8: {
72 net = ntohllNew(net);
73 return;
74 }
75 default: {
76 return;
77 }
78 }
79 } else {
80 return;
81 }
82 }
83
84 /// @brief Stores the bits of a number into a character array.
85 /// @tparam return_type the type of the number.
86 /// @param to the character array to store the bits.
87 /// @param num the number whose bits are to be stored.
88 template<typename return_type, typename value_type> DCA_INLINE void storeBits(value_type* to, return_type num) {
89 static constexpr uint8_t byteSize{ 8 };
91
92 // store the bits of the number in the character array
93 for (uint64_t x = 0; x < sizeof(return_type); ++x) {
94 to[x] = static_cast<value_type>(num >> (byteSize * x));
95 }
96 }
97
98 /// @brief Exception class for etf parsing errors.
99 struct etf_parse_error : public dca_exception {
100 /// @brief Constructs an etf_parse_error instance with a message and source location.
101 /// @param message the error message.
102 /// @param location the source location where the error occurred.
103 DCA_INLINE explicit etf_parse_error(const jsonifier::string_view& message, std::source_location location = std::source_location::current())
104 : dca_exception{ message, location } {};
105 };
106
107 enum class etf_type : int8_t {
108 New_Float_Ext = 70,
109 Small_Integer_Ext = 97,
110 Integer_Ext = 98,
111 Atom_Ext = 100,
112 Nil_Ext = 106,
113 String_Ext = 107,
114 List_Ext = 108,
115 Binary_Ext = 109,
116 Small_Big_Ext = 110,
117 Small_Atom_Ext = 115,
118 Map_Ext = 116,
119 };
120
121 constexpr uint8_t formatVersion{ 131 };
122
123 /// @brief Class for parsing etf data into json format.
124 class DiscordCoreAPI_Dll etf_parser : public jsonifier_internal::alloc_wrapper<uint8_t> {
125 public:
126 friend class websocket_client;
127 using allocator = jsonifier_internal::alloc_wrapper<uint8_t>;
128
129 /// @brief Parse etf data to json format.
130 /// @param dataToParse the etf data to be parsed.
131 /// @return the json representation of the parsed data.
132 DCA_INLINE jsonifier::string_view_base<uint8_t> parseEtfToJson(jsonifier::string_view_base<uint8_t> dataToParse) {
133 dataBuffer = dataToParse.data();
134 dataSize = dataToParse.size();
135 finalString.clear();
136 currentSize = 0;
137 offSet = 0;
138 if (readBitsFromBuffer<uint8_t>() != formatVersion) {
139 throw etf_parse_error{ "etf_parser::parseEtfToJson() error: incorrect format version specified." };
140 }
141 singleValueETFToJson();
142 return { finalString.data(), currentSize };
143 }
144
145 protected:
146 jsonifier::string_base<uint8_t> finalString{};///< The final json string.
147 const uint8_t* dataBuffer{};///< Pointer to etf data buffer.
148 uint64_t currentSize{};///< c///< current size of the json string.
149 uint64_t dataSize{};///< Size of the etf data.
150 uint64_t offSet{};///< current offset in the etf data.
151
152 /// @brief Read bits from the data buffer and convert to return_type.
153 /// @tparam return_type the type to convert the read data to.
154 /// @return the converted value.
155 template<typename return_type> DCA_INLINE return_type readBitsFromBuffer() {
156 if (offSet + sizeof(return_type) > dataSize) {
157 throw etf_parse_error{ "etf_parser::readBitsFromBuffer() error: readBitsFromBuffer() past end of the buffer." };
158 }
159 return_type newValue{};
160 std::memcpy(&newValue, dataBuffer + offSet, sizeof(return_type));
161 offSet += sizeof(return_type);
162 reverseByteOrder(newValue);
163 return newValue;
164 }
165
166 /// @brief Write characters to the final json string.
167 /// @param data pointer to the data to be written.
168 /// @param length number of characters to write.
169 DCA_INLINE void writeCharacters(const char* data, uint64_t length) {
170 if (finalString.size() < currentSize + length) {
171 finalString.resize((finalString.size() + length) * 2);
172 }
173 std::memcpy(finalString.data() + currentSize, data, length);
174 currentSize += length;
175 }
176
177 /// @brief Write characters to the final json string.
178 /// @param data pointer to the data to be written.
179 /// @param length number of characters to write.
180 template<uint64_t size> DCA_INLINE void writeCharacters(const char (&data)[size]) {
181 if (finalString.size() < currentSize + size - 1) {
182 finalString.resize((finalString.size() + size - 1) * 2);
183 }
184 std::memcpy(finalString.data() + currentSize, data, size - 1);
185 currentSize += size - 1;
186 }
187
188 /// @brief Write characters from the buffer to the final json string.
189 /// @param length number of characters to write from the buffer.
190 DCA_INLINE void writeCharactersFromBuffer(uint32_t length) {
191 if (!length) {
192 writeCharacters("\"\"");
193 return;
194 }
195 if (offSet + static_cast<uint64_t>(length) > dataSize) {
196 throw etf_parse_error{ "erl_packer::writeCharactersFromBuffer() error: read past end of buffer." };
197 }
198 if (finalString.size() < currentSize + length) {
199 finalString.resize((finalString.size() + length) * 2);
200 }
201 const uint8_t* stringNew = dataBuffer + offSet;
202 offSet += length;
203 if (length >= 3 && length <= 5) {
204 if (length == 3 && stringNew[0] == 'n' && stringNew[1] == 'i' && stringNew[2] == 'l') {
205 writeCharacters("null");
206 return;
207 } else if (length == 4 && stringNew[0] == 'n' && stringNew[1] == 'u' && stringNew[2] == 'l' && stringNew[3] == 'l') {
208 writeCharacters("null");
209 return;
210 } else if (length == 4 && stringNew[0] == 't' && stringNew[1] == 'r' && stringNew[2] == 'u' && stringNew[3] == 'e') {
211 writeCharacters("true");
212 return;
213 } else if (length == 5 && stringNew[0] == 'f' && stringNew[1] == 'a' && stringNew[2] == 'l' && stringNew[3] == 's' && stringNew[4] == 'e') {
214 writeCharacters("false");
215 return;
216 }
217 }
218 writeCharacter<'"'>();
219 for (uint64_t x = 0; x < length; ++x) {
220 switch (stringNew[x]) {
221 case '\\': {
222 switch (stringNew[++x]) {
223 case '\"':
224 writeCharacter<'\"'>();
225 break;
226 case '\\':
227 writeCharacter<'\\'>();
228 writeCharacter<'\\'>();
229 break;
230 case 'b':
231 writeCharacter<'\b'>();
232 break;
233 case 'f':
234 writeCharacter<'\f'>();
235 break;
236 case 'n':
237 writeCharacter<'\n'>();
238 break;
239 case 'r':
240 writeCharacter<'\r'>();
241 break;
242 case 't':
243 writeCharacter<'\t'>();
244 break;
245 default: {
246 writeCharacter(stringNew[x]);
247 break;
248 }
249 }
250 break;
251 }
252 case '"': {
253 writeCharacter<'\\'>();
254 writeCharacter<'\"'>();
255 break;
256 }
257 default: {
258 writeCharacter(stringNew[x]);
259 break;
260 }
261 }
262 }
263 writeCharacter<'"'>();
264 }
265
266 /// @brief Write a character to the final json string.
267 /// @param value the character to write.
268 template<typename value_type> DCA_INLINE void writeCharacter(const value_type value) {
269 if (finalString.size() < currentSize + 1) {
270 finalString.resize((finalString.size() + 1) * 2);
271 }
272 allocator::construct(&finalString[currentSize++], static_cast<uint8_t>(value));
273 }
274
275 /// @brief Write a character to the final json string.
276 /// @tparam value the character to write.
277 template<const char charToWrite> DCA_INLINE void writeCharacter() {
278 if (finalString.size() < currentSize + 1) {
279 finalString.resize((finalString.size() + 1) * 2);
280 }
281 allocator::construct(&finalString[currentSize++], static_cast<uint8_t>(charToWrite));
282 }
283
284 /// @brief Parse a single etf value and convert to json.
285 DCA_INLINE void singleValueETFToJson() {
286 if (offSet > dataSize) {
287 throw etf_parse_error{ "erl_packer::singleValueETFToJson() error: read past end of buffer." };
288 }
289 uint8_t type = readBitsFromBuffer<uint8_t>();
290 switch (static_cast<etf_type>(type)) {
291 case etf_type::New_Float_Ext: {
292 return parseNewFloatExt();
293 }
294 case etf_type::Small_Integer_Ext: {
295 return parseSmallIntegerExt();
296 }
297 case etf_type::Integer_Ext: {
298 return parseIntegerExt();
299 }
300 case etf_type::Atom_Ext: {
301 return parseAtomExt();
302 }
303 case etf_type::Nil_Ext: {
304 return parseNilExt();
305 }
306 case etf_type::String_Ext: {
307 return parseStringExt();
308 }
309 case etf_type::List_Ext: {
310 return parseListExt();
311 }
312 case etf_type::Binary_Ext: {
313 return parseBinaryExt();
314 }
315 case etf_type::Small_Big_Ext: {
316 return parseSmallBigExt();
317 }
318 case etf_type::Small_Atom_Ext: {
319 return parseSmallAtomExt();
320 }
321 case etf_type::Map_Ext: {
322 return parseMapExt();
323 }
324 default: {
325 throw etf_parse_error{ "etf_parser::singleValueETFToJson() error: unknown data type in etf, the type: " + jsonifier::toString(type) };
326 }
327 }
328 }
329
330 /// @brief Parse etf data representing a list and convert to json array.
331 DCA_INLINE void parseListExt() {
332 uint32_t length = readBitsFromBuffer<uint32_t>();
333 writeCharacter<'['>();
334 if (static_cast<uint64_t>(offSet) + length > dataSize) {
335 throw etf_parse_error{ "erl_packer::parseListExt() error: read past end of buffer." };
336 }
337 for (uint16_t x = 0; x < length; ++x) {
338 singleValueETFToJson();
339 if (x < length - 1) {
340 writeCharacter<','>();
341 }
342 }
343 readBitsFromBuffer<uint8_t>();
344 writeCharacter<']'>();
345 }
346
347 /// @brief Parse etf data representing a small integer and convert to json number.
348 DCA_INLINE void parseSmallIntegerExt() {
349 auto string = jsonifier::toString(readBitsFromBuffer<uint8_t>());
350 writeCharacters(string.data(), string.size());
351 }
352
353 /// @brief Parse etf data representing an integer and convert to json number.
354 DCA_INLINE void parseIntegerExt() {
355 auto string = jsonifier::toString(readBitsFromBuffer<uint32_t>());
356 writeCharacters(string.data(), string.size());
357 }
358
359 /// @brief Parse etf data representing a string and convert to json string.
360 DCA_INLINE void parseStringExt() {
361 writeCharacter<'"'>();
362 uint16_t length = readBitsFromBuffer<uint16_t>();
363 if (static_cast<uint64_t>(offSet) + length > dataSize) {
364 throw etf_parse_error{ "erl_packer::parseStringExt() error: read past end of buffer." };
365 }
366 for (uint16_t x = 0; x < length; ++x) {
367 parseSmallIntegerExt();
368 }
369 writeCharacter<'"'>();
370 }
371
372 /// @brief Parse etf data representing a new float and convert to json number.
373 DCA_INLINE void parseNewFloatExt() {
374 uint64_t value = readBitsFromBuffer<uint64_t>();
375 double newDouble{};
376 std::memcpy(&newDouble, &value, sizeof(double));
377 jsonifier::string valueNew = jsonifier::toString(newDouble);
378 writeCharacters(valueNew.data(), valueNew.size());
379 }
380
381 /// @brief Parse etf data representing a small big integer and convert to json number.
382 DCA_INLINE void parseSmallBigExt() {
383 auto digits = readBitsFromBuffer<uint8_t>();
384 uint8_t sign = readBitsFromBuffer<uint8_t>();
385
386 if (digits > 8) {
387 throw etf_parse_error{ "etf_parser::parseSmallBigExt() error: big integers larger than 8 bytes not supported." };
388 }
389
390 uint64_t value = 0;
391 uint64_t bits = 1;
392 for (uint8_t x = 0; x < digits; ++x) {
393 uint64_t digit = readBitsFromBuffer<uint8_t>();
394 value += digit * bits;
395 bits <<= 8;
396 }
397
398 if (sign == 0) {
399 auto string = jsonifier::toString(value);
400 writeCharacters(string.data(), string.size());
401 } else {
402 auto string = jsonifier::toString(-(static_cast<int64_t>(value)));
403 writeCharacters(string.data(), string.size());
404 }
405 }
406
407 /// @brief Parse etf data representing an atom and convert to json string.
408 DCA_INLINE void parseAtomExt() {
409 writeCharactersFromBuffer(readBitsFromBuffer<uint16_t>());
410 }
411
412 /// @brief Parse etf data representing a binary and convert to json string.
413 DCA_INLINE void parseBinaryExt() {
414 writeCharactersFromBuffer(readBitsFromBuffer<uint32_t>());
415 }
416
417 /// @brief Parse etf data representing a nil value and convert to json null.
418 DCA_INLINE void parseNilExt() {
419 writeCharacters("[]");
420 }
421
422 /// @brief Parse etf data representing a small atom and convert to json string.
423 DCA_INLINE void parseSmallAtomExt() {
424 writeCharactersFromBuffer(readBitsFromBuffer<uint8_t>());
425 }
426
427 /// @brief Parse etf data representing a map and convert to json object.
428 DCA_INLINE void parseMapExt() {
429 uint32_t length = readBitsFromBuffer<uint32_t>();
430 writeCharacter<'{'>();
431 for (uint32_t x = 0; x < length; ++x) {
432 singleValueETFToJson();
433 writeCharacter<':'>();
434 singleValueETFToJson();
435 if (x < length - 1) {
436 writeCharacter<','>();
437 }
438 }
439 writeCharacter<'}'>();
440 }
441 };
442
443 /// @brief Custom exception class for etf serialization errors.
444 struct etf_serialize_error : public dca_exception {
445 public:
446 /// @brief Constructor for etf_serialize_error.
447 /// @param message the error message.
448 /// @param location source location where the error occurred.
449 DCA_INLINE etf_serialize_error(const jsonifier::string_view& message, std::source_location location = std::source_location::current()) : dca_exception{ message, location } {};
450 };
451
452 /// @brief Enumeration for different json value types.
453 enum class json_type : uint8_t { null_t = 0, object_t = 1, array_t = 2, string_t = 3, float_t = 4, uint_t = 5, int_t = 6, bool_t = 7 };
454
455 /// @brief Concept for array types excluding etf_serializer.
456 template<typename value_type>
457 concept array_t = jsonifier::concepts::range<value_type> && jsonifier::concepts::has_resize<jsonifier_internal::unwrap_t<value_type>> &&
458 jsonifier::concepts::has_emplace_back<jsonifier_internal::unwrap_t<value_type>> && jsonifier::concepts::vector_subscriptable<jsonifier_internal::unwrap_t<value_type>> &&
459 requires(value_type&& data) { typename value_type::value_type; };
460
461 /// @brief Concept for object (associative container) types excluding etf_serializer.
462 template<typename value_type>
463 concept object_t = requires(value_type data) {
464 typename value_type::mapped_type;
465 typename value_type::key_type;
466 } && jsonifier::concepts::range<value_type>;
467
468 class etf_serializer {
469 public:
470 template<typename value_type> using allocator = jsonifier_internal::alloc_wrapper<value_type>;
471 using object_type = unordered_map<jsonifier::string, etf_serializer>;
472 using array_type = jsonifier::vector<etf_serializer>;
473 using string_type = jsonifier::string;
474 using float_type = double;
475 using uint_type = uint64_t;
476 using int_type = int64_t;
477 using bool_type = bool;
478
479 DCA_INLINE etf_serializer() = default;
480
481 DCA_INLINE etf_serializer& operator=(etf_serializer&& data) noexcept {
482 destroy();
483 stringReal = std::move(data.stringReal);
484 type = data.type;
485 data.type = json_type::null_t;
486 switch (type) {
487 case json_type::object_t: {
488 objectValue = data.objectValue;
489 data.objectValue = nullptr;
490 break;
491 }
492 case json_type::array_t: {
493 arrayValue = data.arrayValue;
494 data.arrayValue = nullptr;
495 break;
496 }
497 case json_type::string_t: {
498 stringValue = data.stringValue;
499 data.stringValue = nullptr;
500 break;
501 }
502 case json_type::float_t: {
503 floatValue = data.floatValue;
504 data.floatValue = nullptr;
505 break;
506 }
507 case json_type::int_t: {
508 intValue = data.intValue;
509 data.intValue = nullptr;
510 break;
511 }
512 case json_type::uint_t: {
513 uintValue = data.uintValue;
514 data.uintValue = nullptr;
515 break;
516 }
517 case json_type::bool_t: {
518 boolValue = data.boolValue;
519 data.boolValue = nullptr;
520 break;
521 }
522 case json_type::null_t: {
523 break;
524 }
525 }
526 return *this;
527 }
528
529 DCA_INLINE etf_serializer(etf_serializer&& data) noexcept {
530 *this = std::move(data);
531 }
532
533 DCA_INLINE etf_serializer& operator=(const etf_serializer& data) {
534 destroy();
535 switch (data.type) {
536 case json_type::object_t: {
537 setValue<json_type::object_t>(data.getObject());
538 break;
539 }
540 case json_type::array_t: {
541 setValue<json_type::array_t>(data.getArray());
542 break;
543 }
544 case json_type::string_t: {
545 setValue<json_type::string_t>(data.getString());
546 break;
547 }
548 case json_type::float_t: {
549 setValue<json_type::float_t>(data.getFloat());
550 break;
551 }
552 case json_type::uint_t: {
553 setValue<json_type::uint_t>(data.getUint());
554 break;
555 }
556 case json_type::int_t: {
557 setValue<json_type::int_t>(data.getInt());
558 break;
559 }
560 case json_type::bool_t: {
561 setValue<json_type::bool_t>(data.getBool());
562 break;
563 }
564 case json_type::null_t: {
565 break;
566 }
567 }
568 stringReal = data.stringReal;
569 return *this;
570 }
571
572 DCA_INLINE etf_serializer(const etf_serializer& data) {
573 *this = data;
574 }
575
576 template<object_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) noexcept {
577 setValue<json_type::object_t>(std::forward<value_type>(data));
578 return *this;
579 }
580
581 template<object_t value_type> DCA_INLINE etf_serializer(value_type&& data) noexcept {
582 *this = std::forward<value_type>(data);
583 }
584
585 template<array_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) noexcept {
586 setValue<json_type::array_t>(std::forward<value_type>(data));
587 return *this;
588 }
589
590 template<array_t value_type> DCA_INLINE etf_serializer(value_type&& data) noexcept {
591 *this = std::forward<value_type>(data);
592 }
593
594 template<jsonifier::concepts::string_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) noexcept {
595 setValue<json_type::string_t>(std::forward<value_type>(data));
596 return *this;
597 }
598
599 template<jsonifier::concepts::string_t value_type> DCA_INLINE etf_serializer(value_type&& data) noexcept {
600 *this = std::forward<value_type>(data);
601 }
602
603 template<uint_type str_length> DCA_INLINE etf_serializer& operator=(const char (&str)[str_length]) {
604 setValue<json_type::string_t>(str);
605 return *this;
606 }
607
608 template<uint_type str_length> DCA_INLINE etf_serializer(const char (&str)[str_length]) {
609 *this = str;
610 }
611
612 template<jsonifier::concepts::float_type value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) {
613 setValue<json_type::float_t>(std::forward<value_type>(data));
614 return *this;
615 }
616
617 template<jsonifier::concepts::float_type value_type> DCA_INLINE etf_serializer(value_type&& data) {
618 *this = std::forward<value_type>(data);
619 }
620
621 template<jsonifier::concepts::integer_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) {
622 if constexpr (jsonifier::concepts::signed_type<value_type>) {
623 setValue<json_type::int_t>(std::forward<value_type>(data));
624 } else if constexpr (jsonifier::concepts::unsigned_type<value_type>) {
625 setValue<json_type::uint_t>(std::forward<value_type>(data));
626 }
627 return *this;
628 }
629
630 template<jsonifier::concepts::integer_t value_type> DCA_INLINE etf_serializer(value_type&& data) {
631 *this = std::forward<value_type>(data);
632 }
633
634 template<jsonifier::concepts::bool_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) {
635 setValue<json_type::bool_t>(std::forward<value_type>(data));
636 return *this;
637 }
638
639 template<jsonifier::concepts::bool_t value_type> DCA_INLINE etf_serializer(value_type&& data) {
640 *this = std::forward<value_type>(data);
641 }
642
643 template<jsonifier::concepts::enum_t value_type> DCA_INLINE etf_serializer& operator=(value_type&& data) noexcept {
644 setValue<json_type::int_t>(static_cast<int_type>(std::forward<value_type>(data)));
645 return *this;
646 }
647
648 template<jsonifier::concepts::enum_t value_type> DCA_INLINE etf_serializer(value_type&& data) noexcept {
649 *this = std::forward<value_type>(data);
650 }
651
652 DCA_INLINE etf_serializer& operator=(json_type data) {
653 destroy();
654 switch (data) {
655 case json_type::object_t: {
656 setValue<json_type::object_t>();
657 break;
658 }
659 case json_type::array_t: {
660 setValue<json_type::array_t>();
661 break;
662 }
663 case json_type::string_t: {
664 setValue<json_type::string_t>();
665 break;
666 }
667 case json_type::float_t: {
668 setValue<json_type::float_t>();
669 break;
670 }
671 case json_type::uint_t: {
672 setValue<json_type::uint_t>();
673 break;
674 }
675 case json_type::int_t: {
676 setValue<json_type::int_t>();
677 break;
678 }
679 case json_type::bool_t: {
680 setValue<json_type::bool_t>();
681 break;
682 }
683 case json_type::null_t: {
684 setValue<json_type::null_t>();
685 break;
686 }
687 }
688 return *this;
689 }
690
691 DCA_INLINE etf_serializer(json_type data) {
692 *this = data;
693 }
694
695 DCA_INLINE json_type getType() const {
696 return type;
697 }
698
699 DCA_INLINE operator jsonifier::string_base<uint8_t>() {
700 stringReal.clear();
701 appendVersion();
702 serializeJsonToEtfString(*this);
703 return stringReal;
704 }
705
706 DCA_INLINE etf_serializer& operator[](typename object_type::key_type&& key) {
707 if (type == json_type::null_t) {
708 setValue<json_type::object_t>();
709 }
710
711 if (type == json_type::object_t) {
712 return getObject().operator[](std::forward<typename object_type::key_type>(key));
713 }
714 throw etf_serialize_error{ "Sorry, but this value's type is not object." };
715 }
716
717 DCA_INLINE etf_serializer& operator[](uint_type index) {
718 if (type == json_type::null_t) {
719 setValue<json_type::array_t>();
720 }
721
722 if (type == json_type::array_t) {
723 if (index >= getArray().size()) {
724 getArray().resize(index + 1);
725 }
726
727 return getArray().at(index);
728 }
729 throw etf_serialize_error{ "Sorry, but this value's type is not array." };
730 }
731
732 DCA_INLINE void emplaceBack(etf_serializer&& data) {
733 if (type == json_type::null_t) {
734 setValue<json_type::array_t>();
735 }
736
737 if (type == json_type::array_t) {
738 getArray().emplace_back(std::move(data));
739 return;
740 }
741 throw etf_serialize_error{ "Sorry, but this value's type is not array." };
742 }
743
744 DCA_INLINE void emplaceBack(const etf_serializer& rhs) {
745 if (type == json_type::null_t) {
746 setValue<json_type::array_t>();
747 }
748
749 if (type == json_type::array_t) {
750 getArray().emplace_back(rhs);
751 return;
752 }
753 throw etf_serialize_error{ "Sorry, but this value's type is not array." };
754 }
755
756 DCA_INLINE bool_type operator==(const etf_serializer& rhs) const {
757 if (rhs.type != type) {
758 return false;
759 }
760 switch (type) {
761 case json_type::object_t: {
762 return *objectValue == *rhs.objectValue;
763 }
764 case json_type::array_t: {
765 return *arrayValue == *rhs.arrayValue;
766 }
767 case json_type::string_t: {
768 return *stringValue == *rhs.stringValue;
769 }
770 case json_type::float_t: {
771 return *floatValue == *rhs.floatValue;
772 }
773 case json_type::uint_t: {
774 return *uintValue == *rhs.uintValue;
775 }
776 case json_type::int_t: {
777 return *intValue == *rhs.intValue;
778 }
779 case json_type::bool_t: {
780 return *boolValue == *rhs.boolValue;
781 }
782 case json_type::null_t: {
783 break;
784 }
785 }
786 return true;
787 }
788
789 DCA_INLINE object_type& getObject() const {
790 if (type != json_type::object_t) {
791 throw etf_serialize_error{ "Sorry, but this value's type is not object!" };
792 }
793 return *objectValue;
794 }
795
796 DCA_INLINE array_type& getArray() const {
797 if (type != json_type::array_t) {
798 throw etf_serialize_error{ "Sorry, but this value's type is not array!" };
799 }
800 return *arrayValue;
801 }
802
803 DCA_INLINE string_type& getString() const {
804 if (type != json_type::string_t) {
805 throw etf_serialize_error{ "Sorry, but this value's type is not string!" };
806 }
807 return *stringValue;
808 }
809
810 DCA_INLINE float_type& getFloat() const {
811 if (type != json_type::float_t) {
812 throw etf_serialize_error{ "Sorry, but this value's type is not float!" };
813 }
814 return *floatValue;
815 }
816
817 DCA_INLINE uint_type& getUint() const {
818 if (type != json_type::uint_t) {
819 throw etf_serialize_error{ "Sorry, but this value's type is not uint!" };
820 }
821 return *uintValue;
822 }
823
824 DCA_INLINE int_type& getInt() const {
825 if (type != json_type::int_t) {
826 throw etf_serialize_error{ "Sorry, but this value's type is not int!" };
827 }
828 return *intValue;
829 }
830
831 DCA_INLINE bool_type& getBool() const {
832 if (type != json_type::bool_t) {
833 throw etf_serialize_error{ "Sorry, but this value's type is not bool!" };
834 }
835 return *boolValue;
836 }
837
838 DCA_INLINE ~etf_serializer() {
839 destroy();
840 }
841
842 protected:
843 jsonifier::string_base<uint8_t> stringReal{};
844 json_type type{ json_type::null_t };
845 union {
846 object_type* objectValue;
847 array_type* arrayValue;
848 string_type* stringValue;
849 float_type* floatValue;
850 uint_type* uintValue;
851 int_type* intValue;
852 bool_type* boolValue;
853 };
854
855 DCA_INLINE void serializeJsonToEtfString(const etf_serializer& dataToParse) {
856 switch (dataToParse.type) {
857 case json_type::object_t: {
858 return writeEtfObject(dataToParse.getObject());
859 }
860 case json_type::array_t: {
861 return writeEtfArray(dataToParse.getArray());
862 }
863 case json_type::string_t: {
864 return writeEtfString(dataToParse.getString());
865 }
866 case json_type::float_t: {
867 return writeEtfFloat(dataToParse.getFloat());
868 }
869 case json_type::uint_t: {
870 return writeEtfUint(dataToParse.getUint());
871 }
872 case json_type::int_t: {
873 return writeEtfInt(dataToParse.getInt());
874 }
875 case json_type::bool_t: {
876 return writeEtfBool(dataToParse.getBool());
877 }
878 case json_type::null_t: {
879 return writeEtfNull();
880 }
881 }
882 }
883
884 DCA_INLINE void writeEtfObject(const object_type& jsonData) {
885 appendMapHeader(static_cast<uint32_t>(jsonData.size()));
886 for (auto& [key, valueNew]: jsonData) {
887 appendBinaryExt(key, static_cast<uint32_t>(key.size()));
888 serializeJsonToEtfString(valueNew);
889 }
890 }
891
892 DCA_INLINE void writeEtfArray(const array_type& jsonData) {
893 appendListHeader(static_cast<uint32_t>(jsonData.size()));
894 for (auto& valueNew: jsonData) {
895 serializeJsonToEtfString(valueNew);
896 }
897 appendNilExt();
898 }
899
900 DCA_INLINE void writeEtfString(const string_type& jsonData) {
901 appendBinaryExt(jsonData, static_cast<uint32_t>(jsonData.size()));
902 }
903
904 DCA_INLINE void writeEtfUint(const uint_type jsonData) {
905 if (jsonData <= std::numeric_limits<uint8_t>::max() && jsonData >= std::numeric_limits<uint8_t>::min()) {
906 appendUint8(static_cast<uint8_t>(jsonData));
907 } else if (jsonData <= std::numeric_limits<uint32_t>::max() && jsonData >= std::numeric_limits<uint32_t>::min()) {
908 appendUint32(static_cast<uint32_t>(jsonData));
909 } else {
910 appendUint64(jsonData);
911 }
912 }
913
914 DCA_INLINE void writeEtfInt(const int_type jsonData) {
915 if (jsonData <= std::numeric_limits<int8_t>::max() && jsonData >= std::numeric_limits<int8_t>::min()) {
916 appendInt8(static_cast<int8_t>(jsonData));
917 } else if (jsonData <= std::numeric_limits<int32_t>::max() && jsonData >= std::numeric_limits<int32_t>::min()) {
918 appendInt32(static_cast<int32_t>(jsonData));
919 } else {
920 appendInt64(jsonData);
921 }
922 }
923
924 DCA_INLINE void writeEtfFloat(const float_type jsonData) {
925 appendNewFloatExt(jsonData);
926 }
927
928 DCA_INLINE void writeEtfBool(const bool_type jsonData) {
929 appendBool(jsonData);
930 }
931
932 DCA_INLINE void writeEtfNull() {
933 appendNil();
934 }
935
936 template<typename value_type> DCA_INLINE void writeString(const value_type* data, uint_type length) {
937 auto oldSize = stringReal.size();
938 stringReal.resize(oldSize + length);
939 std::memcpy(stringReal.data() + oldSize, data, length);
940 }
941
942 DCA_INLINE void appendBinaryExt(jsonifier::string_view bytes, uint32_t sizeNew) {
943 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::Binary_Ext) };
944 storeBits(newBuffer + 1, sizeNew);
945 writeString(newBuffer, std::size(newBuffer));
946 writeString(bytes.data(), bytes.size());
947 }
948
949 DCA_INLINE void appendNewFloatExt(const float_type newFloat) {
950 uint8_t newBuffer[9]{ static_cast<uint8_t>(etf_type::New_Float_Ext) };
951 uint_type newValue{};
952 std::memcpy(&newValue, &newFloat, sizeof(newFloat));
953 storeBits(newBuffer + 1, newValue);
954 writeString(newBuffer, std::size(newBuffer));
955 }
956
957 DCA_INLINE void appendListHeader(const uint32_t sizeNew) {
958 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::List_Ext) };
959 storeBits(newBuffer + 1, sizeNew);
960 writeString(newBuffer, std::size(newBuffer));
961 }
962
963 DCA_INLINE void appendMapHeader(const uint32_t sizeNew) {
964 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::Map_Ext) };
965 storeBits(newBuffer + 1, sizeNew);
966 writeString(newBuffer, std::size(newBuffer));
967 }
968
969 DCA_INLINE void appendUint64(uint_type valueNew) {
970 uint8_t newBuffer[11]{ static_cast<uint8_t>(etf_type::Small_Big_Ext) };
971 uint8_t encodedBytes{};
972 while (valueNew > 0) {
973 newBuffer[3 + encodedBytes] = static_cast<uint8_t>(valueNew & 0xFF);
974 valueNew >>= 8;
975 ++encodedBytes;
976 }
977 newBuffer[1] = encodedBytes;
978 newBuffer[2] = 0;
979 writeString(newBuffer, 1ull + 2ull + static_cast<uint_type>(encodedBytes));
980 }
981
982 DCA_INLINE void appendInt64(int_type valueNew) {
983 uint8_t newBuffer[11]{ static_cast<uint8_t>(etf_type::Small_Big_Ext) };
984 uint8_t encodedBytes{};
985 while (valueNew > 0) {
986 newBuffer[3 + encodedBytes] = static_cast<uint8_t>(valueNew & 0xFF);
987 valueNew >>= 8;
988 ++encodedBytes;
989 }
990 newBuffer[1] = encodedBytes;
991 if (valueNew >= 0) {
992 newBuffer[2] = 0;
993 } else {
994 newBuffer[2] = 1;
995 }
996 writeString(newBuffer, 1ull + 2ull + static_cast<uint_type>(encodedBytes));
997 }
998
999 DCA_INLINE void appendUint32(const uint32_t valueNew) {
1000 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::Integer_Ext) };
1001 storeBits(newBuffer + 1, valueNew);
1002 writeString(newBuffer, std::size(newBuffer));
1003 }
1004
1005 DCA_INLINE void appendInt32(const int32_t valueNew) {
1006 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::Integer_Ext) };
1007 storeBits(newBuffer + 1, valueNew);
1008 writeString(newBuffer, std::size(newBuffer));
1009 }
1010
1011 DCA_INLINE void appendUint8(const uint8_t valueNew) {
1012 uint8_t newBuffer[2]{ static_cast<uint8_t>(etf_type::Small_Integer_Ext), static_cast<uint8_t>(valueNew) };
1013 writeString(newBuffer, std::size(newBuffer));
1014 }
1015
1016 DCA_INLINE void appendInt8(const int8_t valueNew) {
1017 uint8_t newBuffer[2]{ static_cast<uint8_t>(etf_type::Small_Integer_Ext), static_cast<uint8_t>(valueNew) };
1018 writeString(newBuffer, std::size(newBuffer));
1019 }
1020
1021 DCA_INLINE void appendBool(bool_type data) {
1022 if (data) {
1023 uint8_t newBuffer[6]{ static_cast<uint8_t>(etf_type::Small_Atom_Ext), static_cast<uint8_t>(4), 't', 'r', 'u', 'e' };
1024 writeString(newBuffer, std::size(newBuffer));
1025
1026 } else {
1027 uint8_t newBuffer[7]{ static_cast<uint8_t>(etf_type::Small_Atom_Ext), static_cast<uint8_t>(5), 'f', 'a', 'l', 's', 'e' };
1028 writeString(newBuffer, std::size(newBuffer));
1029 }
1030 }
1031
1032 DCA_INLINE void appendVersion() {
1033 uint8_t newBuffer[1]{ static_cast<uint8_t>(formatVersion) };
1034 writeString(newBuffer, std::size(newBuffer));
1035 }
1036
1037 DCA_INLINE void appendNilExt() {
1038 uint8_t newBuffer[1]{ static_cast<uint8_t>(etf_type::Nil_Ext) };
1039 writeString(newBuffer, std::size(newBuffer));
1040 }
1041
1042 DCA_INLINE void appendNil() {
1043 uint8_t newBuffer[5]{ static_cast<uint8_t>(etf_type::Small_Atom_Ext), static_cast<uint8_t>(3), 'n', 'i', 'l' };
1044 writeString(newBuffer, std::size(newBuffer));
1045 }
1046
1047 template<json_type typeNew, typename... value_types> DCA_INLINE void setValue(value_types&&... args) {
1048 destroy();
1049 type = typeNew;
1050 if constexpr (typeNew == json_type::object_t) {
1051 allocator<object_type> alloc{};
1052 objectValue = alloc.allocate(1);
1053 alloc.construct(objectValue, std::forward<value_types>(args)...);
1054 } else if constexpr (typeNew == json_type::array_t) {
1055 allocator<array_type> alloc{};
1056 arrayValue = alloc.allocate(1);
1057 alloc.construct(arrayValue, std::forward<value_types>(args)...);
1058 } else if constexpr (typeNew == json_type::string_t) {
1059 allocator<string_type> alloc{};
1060 stringValue = alloc.allocate(1);
1061 alloc.construct(stringValue, std::forward<value_types>(args)...);
1062 } else if constexpr (typeNew == json_type::float_t) {
1063 allocator<float_type> alloc{};
1064 floatValue = alloc.allocate(1);
1065 alloc.construct(floatValue, std::forward<value_types>(args)...);
1066 } else if constexpr (typeNew == json_type::uint_t) {
1067 allocator<uint_type> alloc{};
1068 uintValue = alloc.allocate(1);
1069 alloc.construct(uintValue, std::forward<value_types>(args)...);
1070 } else if constexpr (typeNew == json_type::int_t) {
1071 allocator<int_type> alloc{};
1072 intValue = alloc.allocate(1);
1073 alloc.construct(intValue, std::forward<value_types>(args)...);
1074 } else if constexpr (typeNew == json_type::bool_t) {
1075 allocator<bool_type> alloc{};
1076 boolValue = alloc.allocate(1);
1077 alloc.construct(boolValue, std::forward<value_types>(args)...);
1078 }
1079 }
1080
1081 DCA_INLINE void destroy() {
1082 switch (type) {
1083 case json_type::object_t: {
1084 allocator<object_type> alloc{};
1085 alloc.destroy(objectValue);
1086 alloc.deallocate(static_cast<object_type*>(objectValue));
1087 objectValue = nullptr;
1088 break;
1089 }
1090 case json_type::array_t: {
1091 allocator<array_type> alloc{};
1092 alloc.destroy(arrayValue);
1093 alloc.deallocate(static_cast<array_type*>(arrayValue));
1094 arrayValue = nullptr;
1095 break;
1096 }
1097 case json_type::string_t: {
1098 allocator<string_type> alloc{};
1099 alloc.destroy(stringValue);
1100 alloc.deallocate(static_cast<string_type*>(stringValue));
1101 stringValue = nullptr;
1102 break;
1103 }
1104 case json_type::float_t: {
1105 allocator<float_type> alloc{};
1106 alloc.destroy(floatValue);
1107 alloc.deallocate(static_cast<float_type*>(floatValue));
1108 floatValue = nullptr;
1109 break;
1110 }
1111 case json_type::uint_t: {
1112 allocator<uint_type> alloc{};
1113 alloc.destroy(uintValue);
1114 alloc.deallocate(static_cast<uint_type*>(uintValue));
1115 uintValue = nullptr;
1116 break;
1117 }
1118 case json_type::int_t: {
1119 allocator<int_type> alloc{};
1120 alloc.destroy(intValue);
1121 alloc.deallocate(static_cast<int_type*>(intValue));
1122 intValue = nullptr;
1123 break;
1124 }
1125 case json_type::bool_t: {
1126 allocator<bool_type> alloc{};
1127 alloc.destroy(boolValue);
1128 alloc.deallocate(static_cast<bool_type*>(boolValue));
1129 boolValue = nullptr;
1130 break;
1131 }
1132 case json_type::null_t: {
1133 break;
1134 }
1135 default: {
1136 break;
1137 }
1138 }
1139 type = json_type::null_t;
1140 }
1141 };
1142
1143 /**@}*/
1144
1145 };
1146
1147 DCA_INLINE thread_local discord_core_internal::etf_parser etfParser{};
1148}// namespace discord_core_internal
Class for parsing etf data into json format.
Definition Etf.hpp:124
DCA_INLINE void parseAtomExt()
Parse etf data representing an atom and convert to json string.
Definition Etf.hpp:408
DCA_INLINE void parseNewFloatExt()
Parse etf data representing a new float and convert to json number.
Definition Etf.hpp:373
DCA_INLINE void writeCharacters(const char(&data)[size])
Write characters to the final json string.
Definition Etf.hpp:180
DCA_INLINE void parseIntegerExt()
Parse etf data representing an integer and convert to json number.
Definition Etf.hpp:354
DCA_INLINE void singleValueETFToJson()
Parse a single etf value and convert to json.
Definition Etf.hpp:285
DCA_INLINE void writeCharacter(const value_type value)
Write a character to the final json string.
Definition Etf.hpp:268
DCA_INLINE void parseNilExt()
Parse etf data representing a nil value and convert to json null.
Definition Etf.hpp:418
DCA_INLINE void parseListExt()
Parse etf data representing a list and convert to json array.
Definition Etf.hpp:331
DCA_INLINE void parseMapExt()
Parse etf data representing a map and convert to json object.
Definition Etf.hpp:428
DCA_INLINE void writeCharactersFromBuffer(uint32_t length)
Write characters from the buffer to the final json string.
Definition Etf.hpp:190
DCA_INLINE jsonifier::string_view_base< uint8_t > parseEtfToJson(jsonifier::string_view_base< uint8_t > dataToParse)
Parse etf data to json format.
Definition Etf.hpp:132
DCA_INLINE void parseStringExt()
Parse etf data representing a string and convert to json string.
Definition Etf.hpp:360
DCA_INLINE return_type readBitsFromBuffer()
Read bits from the data buffer and convert to return_type.
Definition Etf.hpp:155
DCA_INLINE void parseSmallIntegerExt()
Parse etf data representing a small integer and convert to json number.
Definition Etf.hpp:348
DCA_INLINE void parseBinaryExt()
Parse etf data representing a binary and convert to json string.
Definition Etf.hpp:413
DCA_INLINE void parseSmallBigExt()
Parse etf data representing a small big integer and convert to json number.
Definition Etf.hpp:382
DCA_INLINE void parseSmallAtomExt()
Parse etf data representing a small atom and convert to json string.
Definition Etf.hpp:423
DCA_INLINE void writeCharacter()
Write a character to the final json string.
Definition Etf.hpp:277
DCA_INLINE void writeCharacters(const char *data, uint64_t length)
Write characters to the final json string.
Definition Etf.hpp:169
Concept for array types excluding etf_serializer.
Definition Etf.hpp:457
Concept for object (associative container) types excluding etf_serializer.
Definition Etf.hpp:463
DCA_INLINE void storeBits(value_type *to, return_type num)
Stores the bits of a number into a character array.
Definition Etf.hpp:88
json_type
Enumeration for different json value types.
Definition Etf.hpp:453
DCA_INLINE void reverseByteOrder(return_type &net)
Reverses the byte order of a value if needed, based on the endianness.
Definition Etf.hpp:60
The main namespace for the forward-facing interfaces.
DCA_INLINE dca_exception(jsonifier::string_view error, std::source_location location=std::source_location::current())
Constructor to create a dca_exception with an error message and optional source location.
Definition Base.hpp:845
Exception class for etf parsing errors.
Definition Etf.hpp:99
DCA_INLINE etf_parse_error(const jsonifier::string_view &message, std::source_location location=std::source_location::current())
Constructs an etf_parse_error instance with a message and source location.
Definition Etf.hpp:103
Custom exception class for etf serialization errors.
Definition Etf.hpp:444
DCA_INLINE etf_serialize_error(const jsonifier::string_view &message, std::source_location location=std::source_location::current())
Constructor for etf_serialize_error.
Definition Etf.hpp:449