34#include "pw_assert/assert.h"
35#include "pw_json/internal/nesting.h"
36#include "pw_span/span.h"
37#include "pw_status/status.h"
38#include "pw_status/status_with_size.h"
39#include "pw_string/type_to_string.h"
75 : json_(std::move(nested)) {}
77 json_impl::NestedJson json_;
109 : json_(std::move(nested)) {}
111 json_impl::NestedJson json_;
123 [[nodiscard]]
constexpr bool IsValue()
const;
124 [[nodiscard]]
constexpr bool IsArray()
const;
125 [[nodiscard]]
constexpr bool IsObject()
const;
127 constexpr operator std::string_view()
const;
128 constexpr const char* data()
const;
129 constexpr size_t size()
const;
130 constexpr size_t max_size()
const;
132 [[nodiscard]]
constexpr bool ok()
const;
133 constexpr Status status()
const;
134 constexpr Status last_status()
const;
135 constexpr void clear();
136 constexpr void clear_status();
155 template <
typename T>
173 [[nodiscard]]
constexpr bool IsValue()
const;
174 [[nodiscard]]
constexpr bool IsArray()
const;
175 [[nodiscard]]
constexpr bool IsObject()
const;
177 constexpr operator std::string_view()
const;
178 constexpr const char* data()
const;
179 constexpr size_t size()
const;
180 constexpr size_t max_size()
const;
182 [[nodiscard]]
constexpr bool ok()
const;
183 constexpr Status status()
const;
184 constexpr Status last_status()
const;
185 constexpr void clear();
186 constexpr void clear_status();
192 template <
typename T>
203 template <
typename Iterable>
208 template <
typename T,
size_t kSize>
226 [[nodiscard]]
constexpr bool IsValue()
const;
227 [[nodiscard]]
constexpr bool IsArray()
const;
228 [[nodiscard]]
constexpr bool IsObject()
const;
230 constexpr operator std::string_view()
const;
231 constexpr const char* data()
const;
232 constexpr size_t size()
const;
233 constexpr size_t max_size()
const;
235 [[nodiscard]]
constexpr bool ok()
const;
236 constexpr Status status()
const;
237 constexpr Status last_status()
const;
238 constexpr void clear();
239 constexpr void clear_status();
255 template <
typename T>
256 constexpr JsonObject&
Add(std::string_view key,
const T& value);
258 template <
typename T>
259 constexpr JsonObject&
Add(std::nullptr_t,
const T& value) =
delete;
285 :
JsonBuilder(buffer, buffer_size, Uninitialized{}) {
291 [[nodiscard]]
constexpr bool IsValue()
const {
296 [[nodiscard]]
constexpr bool IsArray()
const {
return buffer_[0] ==
'['; }
299 [[nodiscard]]
constexpr bool IsObject()
const {
return buffer_[0] ==
'{'; }
302 constexpr operator std::string_view()
const {
return {
data(),
size()}; }
305 constexpr const char*
data()
const {
return buffer_; }
308 constexpr size_t size()
const {
return json_size_; }
311 constexpr size_t max_size()
const {
return max_size_; }
314 [[nodiscard]]
constexpr bool ok()
const {
return status().
ok(); }
330 constexpr Status status()
const {
return static_cast<Status::Code
>(status_); }
335 return static_cast<Status::Code
>(last_status_);
339 constexpr void clear() { JsonValueClear(); }
345 template <
typename T>
385 enum class Uninitialized {};
388 constexpr JsonBuilder(
char* buffer,
size_t buffer_size, Uninitialized)
390 max_size_(buffer_size - 1),
396 constexpr void MakeNull() {
405 constexpr void set_json_size(
size_t json_size) { json_size_ = json_size; }
413 friend class JsonValue;
414 friend class JsonArray;
415 friend class JsonObject;
417 friend class NestedJsonArray;
418 friend class NestedJsonObject;
420 constexpr size_t remaining()
const {
return max_size() -
size(); }
423 constexpr void update_status(Status new_status);
427 constexpr void JsonValueClear() {
432 constexpr void JsonArrayClear() {
437 constexpr void JsonObjectClear() {
442 template <
typename T>
443 constexpr Status JsonValueSet(
const T& value);
445 template <
typename T>
446 constexpr JsonArray& JsonArrayAppend(
const T& value);
448 template <
typename Iterator>
449 constexpr JsonArray& JsonArrayExtend(Iterator begin, Iterator end);
451 template <
typename T>
452 constexpr JsonObject& JsonObjectAdd(std::string_view key,
const T& value);
454 [[nodiscard]]
constexpr bool JsonArrayAddElement();
457 [[nodiscard]]
constexpr bool JsonObjectAddKey(std::string_view key);
459 constexpr size_t NestedJsonOffset(
const json_impl::Nesting& nesting)
const {
462 return json_size_ - 3 - nesting.depth();
465 constexpr json_impl::Nesting::Type type()
const {
466 return IsArray() ? json_impl::Nesting::kArray : json_impl::Nesting::kObject;
469 constexpr json_impl::NestedJson JsonArrayAppendNested(
470 const char (&open_close)[2],
const json_impl::Nesting& nesting);
472 constexpr json_impl::NestedJson JsonObjectAddNested(
473 std::string_view key,
474 const char (&open_close)[2],
475 const json_impl::Nesting& nesting);
479 constexpr void AddNestedStart(
const json_impl::Nesting& nesting);
480 constexpr void AddNestedFinish(
const json_impl::Nesting& nesting);
482 template <
typename T>
483 constexpr void NestedJsonArrayAppend(
const T& value,
484 const json_impl::Nesting& nesting);
486 template <
typename T>
487 constexpr void NestedJsonObjectAdd(std::string_view key,
489 const json_impl::Nesting& nesting);
492 constexpr Status HandleSet(StatusWithSize written);
496 constexpr void HandleAdd(StatusWithSize written,
497 size_t starting_size,
500 constexpr void MakeEmpty(
char open,
char close) {
515 uint8_t last_status_;
520template <
size_t kMaxSize>
525 :
JsonBuilder(static_buffer_,
sizeof(static_buffer_), Uninitialized{}),
530 template <
typename T>
531 static constexpr JsonBuffer Value(
const T& initial_value) {
543 template <
size_t kOtherSize>
553 template <
size_t kOtherSize>
559 static constexpr size_t max_size() {
return kMaxSize; }
563 "JsonBuffers require at least 4 bytes");
565 template <
size_t kOtherSize>
567 static_assert(kOtherSize <= kMaxSize,
568 "A JsonBuffer cannot be copied into a smaller buffer");
572 constexpr void CopyFrom(
const JsonBuilder& other) {
573 for (
size_t i = 0; i < other.
size() + 1 ; ++i) {
574 static_buffer_[i] = other.
data()[i];
576 JsonBuilder::set_json_size(other.
size());
580 char static_buffer_[kMaxSize + 1];
587inline constexpr char kArray[2] = {
'[',
']'};
588inline constexpr char kObject[2] = {
'{',
'}'};
590constexpr StatusWithSize WriteString(std::string_view value,
593 if (value.size() + 1 > remaining) {
594 return StatusWithSize::ResourceExhausted();
596 for (
char c : value) {
600 return StatusWithSize(value.size());
603constexpr char NibbleToHex(uint8_t nibble) {
604 return nibble + (nibble < 10 ?
'0' : (
'a' - 10));
620constexpr int EscapedStringCopy(
char* destination,
622 std::string_view source) {
623 int destination_index = 0;
625 for (
char source_char : source) {
626 if (destination_index >= copy_limit) {
630 char escaped_character =
'\0';
632 if (source_char >=
'\b' && source_char <=
'\r' && source_char !=
'\v') {
633 constexpr char kControlChars[] = {
'b',
't',
'n',
'?',
'f',
'r'};
634 escaped_character = kControlChars[source_char -
'\b'];
635 }
else if (source_char ==
'"' || source_char ==
'\\') {
636 escaped_character = source_char;
637 }
else if (source_char >=
' ' && source_char <=
'~') {
639 destination[destination_index++] = source_char;
644 if (copy_limit - destination_index < 6) {
648 destination[destination_index++] =
'\\';
649 destination[destination_index++] =
'u';
650 destination[destination_index++] =
'0';
651 destination[destination_index++] =
'0';
652 destination[destination_index++] = NibbleToHex((source_char >> 4) & 0x0f);
653 destination[destination_index++] = NibbleToHex(source_char & 0x0f);
658 if (copy_limit - destination_index < 2) {
662 destination[destination_index++] =
'\\';
663 destination[destination_index++] = escaped_character;
665 return destination_index;
670constexpr StatusWithSize WriteQuotedString(std::string_view value,
672 size_t buffer_size) {
673 constexpr size_t kOverhead = 2 + 1 ;
674 if (value.size() + kOverhead > buffer_size) {
675 return StatusWithSize::ResourceExhausted();
680 EscapedStringCopy(buffer + 1 , buffer_size - kOverhead, value);
682 return StatusWithSize::ResourceExhausted();
686 buffer[written + 1] =
'"';
687 buffer[written + 2] =
'\0';
688 return StatusWithSize(written + 2);
691constexpr StatusWithSize WriteCharPointer(
const char* ptr,
693 size_t buffer_size) {
694 if (ptr ==
nullptr) {
695 return WriteString(
"null", buffer, buffer_size);
697 return WriteQuotedString(ptr, buffer, buffer_size);
701inline constexpr bool kIsJson =
702 std::is_base_of_v<JsonValue, T> || std::is_base_of_v<JsonArray, T> ||
703 std::is_base_of_v<JsonObject, T>;
709 const char (&open_close)[2];
716 if constexpr (kIsJson<T>) {
717 return WriteString(value, buffer, remaining);
718 }
else if constexpr (std::is_same_v<T, LiteralChars>) {
720 std::string_view(value.open_close, 2), buffer, remaining);
721 }
else if constexpr (std::is_null_pointer_v<T> ||
722 std::is_same_v<T, char*> ||
723 std::is_same_v<T, const char*>) {
724 return WriteCharPointer(value, buffer, remaining);
725 }
else if constexpr (std::is_convertible_v<T, std::string_view>) {
726 return WriteQuotedString(value, buffer, remaining);
727 }
else if constexpr (std::is_floating_point_v<T>) {
728 return string::FloatAsIntToString(value, {buffer, remaining});
729 }
else if constexpr (std::is_same_v<T, bool>) {
730 return WriteString(value ?
"true" :
"false", buffer, remaining);
731 }
else if constexpr (std::is_integral_v<T>) {
732 return string::IntToString(value, {buffer, remaining});
734 static_assert(InvalidJsonType<T>(),
735 "JSON values may only be numbers, strings, JSON arrays, JSON "
737 return StatusWithSize::Internal();
746#define PW_JSON_COMMON_INTERFACE_IMPL(name) \
747 constexpr bool name::IsValue() const { \
748 return static_cast<const JsonBuilder*>(this)->IsValue(); \
750 constexpr bool name::IsArray() const { \
751 return static_cast<const JsonBuilder*>(this)->IsArray(); \
753 constexpr bool name::IsObject() const { \
754 return static_cast<const JsonBuilder*>(this)->IsObject(); \
756 constexpr name::operator std::string_view() const { \
757 return static_cast<const JsonBuilder*>(this)->operator std::string_view(); \
759 constexpr const char* name::data() const { \
760 return static_cast<const JsonBuilder*>(this)->data(); \
762 constexpr size_t name::size() const { \
763 return static_cast<const JsonBuilder*>(this)->size(); \
765 constexpr size_t name::max_size() const { \
766 return static_cast<const JsonBuilder*>(this)->max_size(); \
768 constexpr bool name::ok() const { \
769 return static_cast<const JsonBuilder*>(this)->ok(); \
771 constexpr Status name::status() const { \
772 return static_cast<const JsonBuilder*>(this)->status(); \
774 constexpr Status name::last_status() const { \
775 return static_cast<const JsonBuilder*>(this)->last_status(); \
777 constexpr void name::clear() { \
778 static_cast<JsonBuilder*>(this)->name##Clear(); \
780 constexpr void name::clear_status() { \
781 static_cast<JsonBuilder*>(this)->clear_status(); \
785PW_JSON_COMMON_INTERFACE_IMPL(JsonValue);
786PW_JSON_COMMON_INTERFACE_IMPL(JsonArray);
787PW_JSON_COMMON_INTERFACE_IMPL(JsonObject);
789#undef PW_JSON_COMMON_INTERFACE_IMPL
793 json_.builder().NestedJsonArrayAppend(value, json_.nesting());
797 return json_.builder().JsonArrayAppendNested(json_impl::kArray,
801 return json_.builder().JsonArrayAppendNested(json_impl::kObject,
805 std::string_view key) {
806 return json_.builder().JsonObjectAddNested(
807 key, json_impl::kArray, json_.nesting());
810 std::string_view key) {
811 return json_.builder().JsonObjectAddNested(
812 key, json_impl::kObject, json_.nesting());
817 json_.builder().NestedJsonObjectAdd(key, value, json_.nesting());
822 return static_cast<JsonBuilder*
>(
this)->JsonValueSet(value);
826 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppend(value);
829 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
830 json_impl::kArray, {});
833 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
834 json_impl::kObject, {});
836template <
typename Iterable>
838 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
839 std::cend(iterable));
841template <
typename T,
size_t kSize>
843 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
844 std::cend(iterable));
848 return static_cast<JsonBuilder*
>(
this)->JsonObjectAdd(key, value);
850constexpr NestedJsonArray JsonObject::AddNestedArray(std::string_view key) {
851 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
852 key, json_impl::kArray, {});
854constexpr NestedJsonObject JsonObject::AddNestedObject(std::string_view key) {
855 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
856 key, json_impl::kObject, {});
863 return HandleSet(json_impl::SerializeJson(value, buffer_, max_size_ + 1));
866constexpr void JsonBuilder::update_status(
Status new_status) {
867 last_status_ = new_status.
code();
869 status_ = new_status.
code();
874constexpr Status JsonBuilder::JsonValueSet(
const T& value) {
875 if constexpr (json_impl::kIsJson<T>) {
876 PW_ASSERT(
this != &value);
877 PW_ASSERT(value.IsValue());
883constexpr JsonArray& JsonBuilder::JsonArrayAppend(
const T& value) {
884 if constexpr (json_impl::kIsJson<T>) {
885 PW_ASSERT(
this != &value);
888 const size_t starting_size =
size();
889 if (JsonArrayAddElement()) {
892 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
899template <
typename Iterator>
900constexpr JsonArray& JsonBuilder::JsonArrayExtend(Iterator begin,
902 const size_t starting_size =
size();
904 for (Iterator cur = begin; cur != end; ++cur) {
907 json_size_ = starting_size;
908 buffer_[
size() - 1] =
']';
909 buffer_[
size()] =
'\0';
917constexpr JsonObject& JsonBuilder::JsonObjectAdd(std::string_view key,
919 if constexpr (json_impl::kIsJson<T>) {
920 PW_ASSERT(
this != &value);
923 const size_t starting_size =
size();
924 if (JsonObjectAddKey(key)) {
927 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
934constexpr bool JsonBuilder::JsonArrayAddElement() {
939 update_status(Status::ResourceExhausted());
947 buffer_[json_size_ - 1] =
',';
948 buffer_[json_size_++] =
' ';
954constexpr bool JsonBuilder::JsonObjectAddKey(std::string_view key) {
961 update_status(Status::ResourceExhausted());
969 buffer_[json_size_ - 1] =
',';
970 buffer_[json_size_++] =
' ';
975 json_impl::WriteQuotedString(key, &buffer_[json_size_], remaining() - 3);
980 json_size_ += written.size();
981 buffer_[json_size_++] =
':';
982 buffer_[json_size_++] =
' ';
986constexpr json_impl::NestedJson JsonBuilder::JsonArrayAppendNested(
987 const char (&open_close)[2],
const json_impl::Nesting& nesting) {
988 AddNestedStart(nesting);
989 json_impl::Nesting::Type nesting_within = type();
990 JsonArrayAppend(json_impl::LiteralChars{open_close});
991 AddNestedFinish(nesting);
992 return json_impl::NestedJson(
995 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
996 : json_impl::Nesting());
999constexpr json_impl::NestedJson JsonBuilder::JsonObjectAddNested(
1000 std::string_view key,
1001 const char (&open_close)[2],
1002 const json_impl::Nesting& nesting) {
1003 AddNestedStart(nesting);
1004 json_impl::Nesting::Type nesting_within = type();
1005 JsonObjectAdd(key, json_impl::LiteralChars{open_close});
1006 AddNestedFinish(nesting);
1007 return json_impl::NestedJson(
1010 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
1011 : json_impl::Nesting());
1014constexpr void JsonBuilder::AddNestedStart(
const json_impl::Nesting& nesting) {
1018 json_size_ >= nesting.offset() + nesting.depth() + 2 );
1020 buffer_[json_size_ - nesting.depth() - 1] ==
1021 buffer_[nesting.offset()] + 2 );
1022 nesting.CheckNesting(&buffer_[json_size_ - nesting.depth()]);
1024 buffer_ += nesting.offset();
1025 json_size_ -= nesting.offset() + nesting.depth();
1026 max_size_ -= nesting.offset() + nesting.depth();
1029constexpr void JsonBuilder::AddNestedFinish(
const json_impl::Nesting& nesting) {
1030 buffer_ -= nesting.offset();
1031 max_size_ += nesting.offset() + nesting.depth();
1033 json_size_ += nesting.offset();
1034 nesting.Terminate(&buffer_[json_size_]);
1035 json_size_ += nesting.depth();
1038template <
typename T>
1039constexpr void JsonBuilder::NestedJsonArrayAppend(
1040 const T& value,
const json_impl::Nesting& nesting) {
1041 AddNestedStart(nesting);
1042 JsonArrayAppend(value);
1043 AddNestedFinish(nesting);
1046template <
typename T>
1047constexpr void JsonBuilder::NestedJsonObjectAdd(
1048 std::string_view key,
const T& value,
const json_impl::Nesting& nesting) {
1049 AddNestedStart(nesting);
1050 JsonObjectAdd(key, value);
1051 AddNestedFinish(nesting);
1054constexpr Status JsonBuilder::HandleSet(StatusWithSize written) {
1056 json_size_ = written.size();
1060 set_statuses(written.status());
1064constexpr void JsonBuilder::HandleAdd(StatusWithSize written,
1065 size_t starting_size,
1067 update_status(written.status());
1069 json_size_ += written.size();
1071 json_size_ = starting_size - 1;
1074 buffer_[json_size_++] = terminator;
1075 buffer_[json_size_] =
'\0';
Definition: builder.h:167
constexpr JsonArray & Append(const T &value)
Definition: builder.h:825
constexpr JsonArray & Extend(const Iterable &iterable)
Definition: builder.h:837
constexpr NestedJsonArray AppendNestedArray()
Appends a nested array to this array.
Definition: builder.h:828
constexpr NestedJsonObject AppendNestedObject()
Appends a nested object to this array.
Definition: builder.h:832
Definition: builder.h:521
Definition: builder.h:274
constexpr Status status() const
Definition: builder.h:330
constexpr bool IsArray() const
True if the top-level JSON entity is an array.
Definition: builder.h:296
constexpr JsonBuilder(char *buffer, size_t buffer_size)
Initializes to the value null. buffer_size must be at least 5.
Definition: builder.h:284
constexpr JsonObject & StartObject()
Definition: builder.h:379
constexpr size_t max_size() const
The maximum size of the JSON string, excluding the null terminator.
Definition: builder.h:311
constexpr bool IsValue() const
True if the top-level JSON entity is a simple value (not array or object).
Definition: builder.h:291
constexpr Status last_status() const
Definition: builder.h:334
constexpr JsonBuilder(span< char > buffer)
Initializes to the value null. buffer.size() must be at least 5.
Definition: builder.h:280
constexpr const char * data() const
Pointer to the serialized JSON, which is always a null-terminated string.
Definition: builder.h:305
constexpr Status SetValue(const T &value)
Clears the JSON and sets it to a single JSON value (see JsonValue::Set).
Definition: builder.h:862
constexpr size_t size() const
The current size of the JSON string, excluding the null terminator.
Definition: builder.h:308
constexpr bool ok() const
True if.
Definition: builder.h:314
constexpr void clear()
Sets the JSON null and clears the status.
Definition: builder.h:339
constexpr JsonArray & StartArray()
Definition: builder.h:364
constexpr void clear_status()
Resets status() and last_status().
Definition: builder.h:342
static constexpr size_t MinBufferSize()
JsonBuilder requires at least 5 characters in its buffer.
Definition: builder.h:277
constexpr JsonValue & StartValue()
Definition: builder.h:350
constexpr bool IsObject() const
True if the top-level JSON entity is an object.
Definition: builder.h:299
Definition: builder.h:220
constexpr JsonObject & Add(std::string_view key, const T &value)
Definition: builder.h:847
Definition: builder.h:117
constexpr Status Set(const T &value)
Definition: builder.h:821
constexpr NestedJsonObject AppendNestedObject()
Appends a new nested object to this nested array.
Definition: builder.h:800
constexpr NestedJsonArray AppendNestedArray()
Appends a new nested array to this nested array.
Definition: builder.h:796
constexpr NestedJsonArray & Append(const T &value)
Appends to the nested array.
Definition: builder.h:792
constexpr NestedJsonArray AddNestedArray(std::string_view key)
Adds a nested array to the nested object.
Definition: builder.h:804
constexpr NestedJsonObject & Add(std::string_view key, const T &value)
Adds a key-value pair to the nested object.
Definition: builder.h:815
constexpr NestedJsonObject AddNestedObject(std::string_view key)
Adds a nested object to the nested object.
Definition: builder.h:809
constexpr Code code() const
Returns the Status::Code (pw_Status) for this Status.
Definition: status.h:152
constexpr bool ok() const
Definition: status.h:157
Definition: status_with_size.h:49
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
constexpr Status OkStatus()
Definition: status.h:234
Definition: builder.h:706
Definition: builder.h:708