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"
77 : json_(std::move(nested)) {}
79 json_impl::NestedJson json_;
111 : json_(std::move(nested)) {}
113 json_impl::NestedJson json_;
125 [[nodiscard]]
constexpr bool IsValue()
const;
126 [[nodiscard]]
constexpr bool IsArray()
const;
127 [[nodiscard]]
constexpr bool IsObject()
const;
129 constexpr operator std::string_view()
const;
130 constexpr const char* data()
const;
131 constexpr size_t size()
const;
132 constexpr size_t max_size()
const;
134 [[nodiscard]]
constexpr bool ok()
const;
135 constexpr Status status()
const;
136 constexpr Status last_status()
const;
137 constexpr void clear();
138 constexpr void clear_status();
157 template <
typename T>
175 [[nodiscard]]
constexpr bool IsValue()
const;
176 [[nodiscard]]
constexpr bool IsArray()
const;
177 [[nodiscard]]
constexpr bool IsObject()
const;
179 constexpr operator std::string_view()
const;
180 constexpr const char* data()
const;
181 constexpr size_t size()
const;
182 constexpr size_t max_size()
const;
184 [[nodiscard]]
constexpr bool ok()
const;
185 constexpr Status status()
const;
186 constexpr Status last_status()
const;
187 constexpr void clear();
188 constexpr void clear_status();
194 template <
typename T>
205 template <
typename Iterable>
210 template <
typename T,
size_t kSize>
228 [[nodiscard]]
constexpr bool IsValue()
const;
229 [[nodiscard]]
constexpr bool IsArray()
const;
230 [[nodiscard]]
constexpr bool IsObject()
const;
232 constexpr operator std::string_view()
const;
233 constexpr const char* data()
const;
234 constexpr size_t size()
const;
235 constexpr size_t max_size()
const;
237 [[nodiscard]]
constexpr bool ok()
const;
238 constexpr Status status()
const;
239 constexpr Status last_status()
const;
240 constexpr void clear();
241 constexpr void clear_status();
257 template <
typename T>
258 constexpr JsonObject&
Add(std::string_view key,
const T& value);
260 template <
typename T>
261 constexpr JsonObject&
Add(std::nullptr_t,
const T& value) =
delete;
287 :
JsonBuilder(buffer, buffer_size, Uninitialized{}) {
293 [[nodiscard]]
constexpr bool IsValue()
const {
298 [[nodiscard]]
constexpr bool IsArray()
const {
return buffer_[0] ==
'['; }
301 [[nodiscard]]
constexpr bool IsObject()
const {
return buffer_[0] ==
'{'; }
304 constexpr operator std::string_view()
const {
return {
data(),
size()}; }
307 constexpr const char*
data()
const {
return buffer_; }
310 constexpr size_t size()
const {
return json_size_; }
313 constexpr size_t max_size()
const {
return max_size_; }
316 [[nodiscard]]
constexpr bool ok()
const {
return status().
ok(); }
332 constexpr Status status()
const {
return static_cast<Status::Code
>(status_); }
337 return static_cast<Status::Code
>(last_status_);
341 constexpr void clear() { JsonValueClear(); }
347 template <
typename T>
387 enum class Uninitialized {};
390 constexpr JsonBuilder(
char* buffer,
size_t buffer_size, Uninitialized)
392 max_size_(buffer_size - 1),
398 constexpr void MakeNull() {
407 constexpr void set_json_size(
size_t json_size) { json_size_ = json_size; }
415 friend class JsonValue;
416 friend class JsonArray;
417 friend class JsonObject;
419 friend class NestedJsonArray;
420 friend class NestedJsonObject;
422 constexpr size_t remaining()
const {
return max_size() -
size(); }
425 constexpr void update_status(Status new_status);
429 constexpr void JsonValueClear() {
434 constexpr void JsonArrayClear() {
439 constexpr void JsonObjectClear() {
444 template <
typename T>
445 constexpr Status JsonValueSet(
const T& value);
447 template <
typename T>
448 constexpr JsonArray& JsonArrayAppend(
const T& value);
450 template <
typename Iterator>
451 constexpr JsonArray& JsonArrayExtend(Iterator begin, Iterator end);
453 template <
typename T>
454 constexpr JsonObject& JsonObjectAdd(std::string_view key,
const T& value);
456 [[nodiscard]]
constexpr bool JsonArrayAddElement();
459 [[nodiscard]]
constexpr bool JsonObjectAddKey(std::string_view key);
461 constexpr size_t NestedJsonOffset(
const json_impl::Nesting& nesting)
const {
464 return json_size_ - 3 - nesting.depth();
467 constexpr json_impl::Nesting::Type type()
const {
468 return IsArray() ? json_impl::Nesting::kArray : json_impl::Nesting::kObject;
471 constexpr json_impl::NestedJson JsonArrayAppendNested(
472 const char (&open_close)[2],
const json_impl::Nesting& nesting);
474 constexpr json_impl::NestedJson JsonObjectAddNested(
475 std::string_view key,
476 const char (&open_close)[2],
477 const json_impl::Nesting& nesting);
481 constexpr void AddNestedStart(
const json_impl::Nesting& nesting);
482 constexpr void AddNestedFinish(
const json_impl::Nesting& nesting);
484 template <
typename T>
485 constexpr void NestedJsonArrayAppend(
const T& value,
486 const json_impl::Nesting& nesting);
488 template <
typename T>
489 constexpr void NestedJsonObjectAdd(std::string_view key,
491 const json_impl::Nesting& nesting);
494 constexpr Status HandleSet(StatusWithSize written);
498 constexpr void HandleAdd(StatusWithSize written,
499 size_t starting_size,
502 constexpr void MakeEmpty(
char open,
char close) {
517 uint8_t last_status_;
522template <
size_t kMaxSize>
527 :
JsonBuilder(static_buffer_,
sizeof(static_buffer_), Uninitialized{}),
532 template <
typename T>
533 static constexpr JsonBuffer Value(
const T& initial_value) {
545 template <
size_t kOtherSize>
555 template <
size_t kOtherSize>
561 static constexpr size_t max_size() {
return kMaxSize; }
565 "JsonBuffers require at least 4 bytes");
567 template <
size_t kOtherSize>
569 static_assert(kOtherSize <= kMaxSize,
570 "A JsonBuffer cannot be copied into a smaller buffer");
574 constexpr void CopyFrom(
const JsonBuilder& other) {
575 for (
size_t i = 0; i < other.
size() + 1 ; ++i) {
576 static_buffer_[i] = other.
data()[i];
578 JsonBuilder::set_json_size(other.
size());
582 char static_buffer_[kMaxSize + 1];
589inline constexpr char kArray[2] = {
'[',
']'};
590inline constexpr char kObject[2] = {
'{',
'}'};
592constexpr StatusWithSize WriteString(std::string_view value,
595 if (value.size() + 1 > remaining) {
596 return StatusWithSize::ResourceExhausted();
598 for (
char c : value) {
602 return StatusWithSize(value.size());
605constexpr char NibbleToHex(uint8_t nibble) {
606 return nibble + (nibble < 10 ?
'0' : (
'a' - 10));
622constexpr int EscapedStringCopy(
char* destination,
624 std::string_view source) {
625 int destination_index = 0;
627 for (
char source_char : source) {
628 if (destination_index >= copy_limit) {
632 char escaped_character =
'\0';
634 if (source_char >=
'\b' && source_char <=
'\r' && source_char !=
'\v') {
635 constexpr char kControlChars[] = {
'b',
't',
'n',
'?',
'f',
'r'};
636 escaped_character = kControlChars[source_char -
'\b'];
637 }
else if (source_char ==
'"' || source_char ==
'\\') {
638 escaped_character = source_char;
639 }
else if (source_char >=
' ' && source_char <=
'~') {
641 destination[destination_index++] = source_char;
646 if (copy_limit - destination_index < 6) {
650 destination[destination_index++] =
'\\';
651 destination[destination_index++] =
'u';
652 destination[destination_index++] =
'0';
653 destination[destination_index++] =
'0';
654 destination[destination_index++] = NibbleToHex((source_char >> 4) & 0x0f);
655 destination[destination_index++] = NibbleToHex(source_char & 0x0f);
660 if (copy_limit - destination_index < 2) {
664 destination[destination_index++] =
'\\';
665 destination[destination_index++] = escaped_character;
667 return destination_index;
672constexpr StatusWithSize WriteQuotedString(std::string_view value,
674 size_t buffer_size) {
675 constexpr size_t kOverhead = 2 + 1 ;
676 if (value.size() + kOverhead > buffer_size) {
677 return StatusWithSize::ResourceExhausted();
682 EscapedStringCopy(buffer + 1 , buffer_size - kOverhead, value);
684 return StatusWithSize::ResourceExhausted();
688 buffer[written + 1] =
'"';
689 buffer[written + 2] =
'\0';
690 return StatusWithSize(written + 2);
693constexpr StatusWithSize WriteCharPointer(
const char* ptr,
695 size_t buffer_size) {
696 if (ptr ==
nullptr) {
697 return WriteString(
"null", buffer, buffer_size);
699 return WriteQuotedString(ptr, buffer, buffer_size);
703inline constexpr bool kIsJson =
704 std::is_base_of_v<JsonValue, T> || std::is_base_of_v<JsonArray, T> ||
705 std::is_base_of_v<JsonObject, T>;
711 const char (&open_close)[2];
718 if constexpr (kIsJson<T>) {
719 return WriteString(value, buffer, remaining);
720 }
else if constexpr (std::is_same_v<T, LiteralChars>) {
722 std::string_view(value.open_close, 2), buffer, remaining);
723 }
else if constexpr (std::is_null_pointer_v<T> ||
724 std::is_same_v<T, char*> ||
725 std::is_same_v<T, const char*>) {
726 return WriteCharPointer(value, buffer, remaining);
727 }
else if constexpr (std::is_convertible_v<T, std::string_view>) {
728 return WriteQuotedString(value, buffer, remaining);
729 }
else if constexpr (std::is_floating_point_v<T>) {
730 return string::FloatAsIntToString(value, {buffer, remaining});
731 }
else if constexpr (std::is_same_v<T, bool>) {
732 return WriteString(value ?
"true" :
"false", buffer, remaining);
733 }
else if constexpr (std::is_integral_v<T>) {
734 return string::IntToString(value, {buffer, remaining});
736 static_assert(InvalidJsonType<T>(),
737 "JSON values may only be numbers, strings, JSON arrays, JSON "
739 return StatusWithSize::Internal();
748#define PW_JSON_COMMON_INTERFACE_IMPL(name) \
749 constexpr bool name::IsValue() const { \
750 return static_cast<const JsonBuilder*>(this)->IsValue(); \
752 constexpr bool name::IsArray() const { \
753 return static_cast<const JsonBuilder*>(this)->IsArray(); \
755 constexpr bool name::IsObject() const { \
756 return static_cast<const JsonBuilder*>(this)->IsObject(); \
758 constexpr name::operator std::string_view() const { \
759 return static_cast<const JsonBuilder*>(this)->operator std::string_view(); \
761 constexpr const char* name::data() const { \
762 return static_cast<const JsonBuilder*>(this)->data(); \
764 constexpr size_t name::size() const { \
765 return static_cast<const JsonBuilder*>(this)->size(); \
767 constexpr size_t name::max_size() const { \
768 return static_cast<const JsonBuilder*>(this)->max_size(); \
770 constexpr bool name::ok() const { \
771 return static_cast<const JsonBuilder*>(this)->ok(); \
773 constexpr Status name::status() const { \
774 return static_cast<const JsonBuilder*>(this)->status(); \
776 constexpr Status name::last_status() const { \
777 return static_cast<const JsonBuilder*>(this)->last_status(); \
779 constexpr void name::clear() { \
780 static_cast<JsonBuilder*>(this)->name##Clear(); \
782 constexpr void name::clear_status() { \
783 static_cast<JsonBuilder*>(this)->clear_status(); \
787PW_JSON_COMMON_INTERFACE_IMPL(JsonValue);
788PW_JSON_COMMON_INTERFACE_IMPL(JsonArray);
789PW_JSON_COMMON_INTERFACE_IMPL(JsonObject);
791#undef PW_JSON_COMMON_INTERFACE_IMPL
795 json_.builder().NestedJsonArrayAppend(value, json_.nesting());
799 return json_.builder().JsonArrayAppendNested(json_impl::kArray,
803 return json_.builder().JsonArrayAppendNested(json_impl::kObject,
807 std::string_view key) {
808 return json_.builder().JsonObjectAddNested(
809 key, json_impl::kArray, json_.nesting());
812 std::string_view key) {
813 return json_.builder().JsonObjectAddNested(
814 key, json_impl::kObject, json_.nesting());
819 json_.builder().NestedJsonObjectAdd(key, value, json_.nesting());
824 return static_cast<JsonBuilder*
>(
this)->JsonValueSet(value);
828 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppend(value);
831 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
832 json_impl::kArray, {});
835 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
836 json_impl::kObject, {});
838template <
typename Iterable>
840 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
841 std::cend(iterable));
843template <
typename T,
size_t kSize>
845 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
846 std::cend(iterable));
850 return static_cast<JsonBuilder*
>(
this)->JsonObjectAdd(key, value);
852constexpr NestedJsonArray JsonObject::AddNestedArray(std::string_view key) {
853 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
854 key, json_impl::kArray, {});
856constexpr NestedJsonObject JsonObject::AddNestedObject(std::string_view key) {
857 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
858 key, json_impl::kObject, {});
865 return HandleSet(json_impl::SerializeJson(value, buffer_, max_size_ + 1));
868constexpr void JsonBuilder::update_status(
Status new_status) {
869 last_status_ = new_status.
code();
871 status_ = new_status.
code();
876constexpr Status JsonBuilder::JsonValueSet(
const T& value) {
877 if constexpr (json_impl::kIsJson<T>) {
878 PW_ASSERT(
this != &value);
879 PW_ASSERT(value.IsValue());
885constexpr JsonArray& JsonBuilder::JsonArrayAppend(
const T& value) {
886 if constexpr (json_impl::kIsJson<T>) {
887 PW_ASSERT(
this != &value);
890 const size_t starting_size =
size();
891 if (JsonArrayAddElement()) {
894 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
901template <
typename Iterator>
902constexpr JsonArray& JsonBuilder::JsonArrayExtend(Iterator begin,
904 const size_t starting_size =
size();
906 for (Iterator cur = begin; cur != end; ++cur) {
909 json_size_ = starting_size;
910 buffer_[
size() - 1] =
']';
911 buffer_[
size()] =
'\0';
919constexpr JsonObject& JsonBuilder::JsonObjectAdd(std::string_view key,
921 if constexpr (json_impl::kIsJson<T>) {
922 PW_ASSERT(
this != &value);
925 const size_t starting_size =
size();
926 if (JsonObjectAddKey(key)) {
929 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
936constexpr bool JsonBuilder::JsonArrayAddElement() {
941 update_status(Status::ResourceExhausted());
949 buffer_[json_size_ - 1] =
',';
950 buffer_[json_size_++] =
' ';
956constexpr bool JsonBuilder::JsonObjectAddKey(std::string_view key) {
963 update_status(Status::ResourceExhausted());
971 buffer_[json_size_ - 1] =
',';
972 buffer_[json_size_++] =
' ';
977 json_impl::WriteQuotedString(key, &buffer_[json_size_], remaining() - 3);
982 json_size_ += written.size();
983 buffer_[json_size_++] =
':';
984 buffer_[json_size_++] =
' ';
988constexpr json_impl::NestedJson JsonBuilder::JsonArrayAppendNested(
989 const char (&open_close)[2],
const json_impl::Nesting& nesting) {
990 AddNestedStart(nesting);
991 json_impl::Nesting::Type nesting_within = type();
992 JsonArrayAppend(json_impl::LiteralChars{open_close});
993 AddNestedFinish(nesting);
994 return json_impl::NestedJson(
997 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
998 : json_impl::Nesting());
1001constexpr json_impl::NestedJson JsonBuilder::JsonObjectAddNested(
1002 std::string_view key,
1003 const char (&open_close)[2],
1004 const json_impl::Nesting& nesting) {
1005 AddNestedStart(nesting);
1006 json_impl::Nesting::Type nesting_within = type();
1007 JsonObjectAdd(key, json_impl::LiteralChars{open_close});
1008 AddNestedFinish(nesting);
1009 return json_impl::NestedJson(
1012 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
1013 : json_impl::Nesting());
1016constexpr void JsonBuilder::AddNestedStart(
const json_impl::Nesting& nesting) {
1020 json_size_ >= nesting.offset() + nesting.depth() + 2 );
1022 buffer_[json_size_ - nesting.depth() - 1] ==
1023 buffer_[nesting.offset()] + 2 );
1024 nesting.CheckNesting(&buffer_[json_size_ - nesting.depth()]);
1026 buffer_ += nesting.offset();
1027 json_size_ -= nesting.offset() + nesting.depth();
1028 max_size_ -= nesting.offset() + nesting.depth();
1031constexpr void JsonBuilder::AddNestedFinish(
const json_impl::Nesting& nesting) {
1032 buffer_ -= nesting.offset();
1033 max_size_ += nesting.offset() + nesting.depth();
1035 json_size_ += nesting.offset();
1036 nesting.Terminate(&buffer_[json_size_]);
1037 json_size_ += nesting.depth();
1040template <
typename T>
1041constexpr void JsonBuilder::NestedJsonArrayAppend(
1042 const T& value,
const json_impl::Nesting& nesting) {
1043 AddNestedStart(nesting);
1044 JsonArrayAppend(value);
1045 AddNestedFinish(nesting);
1048template <
typename T>
1049constexpr void JsonBuilder::NestedJsonObjectAdd(
1050 std::string_view key,
const T& value,
const json_impl::Nesting& nesting) {
1051 AddNestedStart(nesting);
1052 JsonObjectAdd(key, value);
1053 AddNestedFinish(nesting);
1056constexpr Status JsonBuilder::HandleSet(StatusWithSize written) {
1058 json_size_ = written.size();
1062 set_statuses(written.status());
1066constexpr void JsonBuilder::HandleAdd(StatusWithSize written,
1067 size_t starting_size,
1069 update_status(written.status());
1071 json_size_ += written.size();
1073 json_size_ = starting_size - 1;
1076 buffer_[json_size_++] = terminator;
1077 buffer_[json_size_] =
'\0';
Definition: builder.h:169
Definition: builder.h:523
Definition: builder.h:276
Definition: builder.h:222
Definition: builder.h:119
constexpr Code code() const
Returns the Status::Code (pw_Status) for this Status.
Definition: status.h:153
constexpr bool ok() const
Definition: status.h:158
Definition: status_with_size.h:49
Definition: span_impl.h:235
constexpr Status status() const
Definition: builder.h:332
constexpr bool IsArray() const
True if the top-level JSON entity is an array.
Definition: builder.h:298
constexpr JsonBuilder(char *buffer, size_t buffer_size)
Initializes to the value null. buffer_size must be at least 5.
Definition: builder.h:286
constexpr JsonObject & StartObject()
Definition: builder.h:381
constexpr size_t max_size() const
The maximum size of the JSON string, excluding the null terminator.
Definition: builder.h:313
constexpr bool IsValue() const
True if the top-level JSON entity is a simple value (not array or object).
Definition: builder.h:293
constexpr Status last_status() const
Definition: builder.h:336
constexpr NestedJsonArray AddNestedArray(std::string_view key)
Adds a nested array to the nested object.
Definition: builder.h:806
constexpr JsonBuilder(span< char > buffer)
Initializes to the value null. buffer.size() must be at least 5.
Definition: builder.h:282
constexpr NestedJsonObject AppendNestedObject()
Appends a new nested object to this nested array.
Definition: builder.h:802
constexpr const char * data() const
Pointer to the serialized JSON, which is always a null-terminated string.
Definition: builder.h:307
constexpr JsonArray & Append(const T &value)
Definition: builder.h:827
constexpr Status Set(const T &value)
Definition: builder.h:823
constexpr NestedJsonArray AppendNestedArray()
Appends a new nested array to this nested array.
Definition: builder.h:798
constexpr Status SetValue(const T &value)
Clears the JSON and sets it to a single JSON value (see JsonValue::Set).
Definition: builder.h:864
constexpr NestedJsonArray & Append(const T &value)
Appends to the nested array.
Definition: builder.h:794
constexpr size_t size() const
The current size of the JSON string, excluding the null terminator.
Definition: builder.h:310
constexpr bool ok() const
True if.
Definition: builder.h:316
constexpr void clear()
Sets the JSON null and clears the status.
Definition: builder.h:341
constexpr JsonArray & Extend(const Iterable &iterable)
Definition: builder.h:839
constexpr NestedJsonArray AppendNestedArray()
Appends a nested array to this array.
Definition: builder.h:830
constexpr JsonArray & StartArray()
Definition: builder.h:366
constexpr NestedJsonObject AppendNestedObject()
Appends a nested object to this array.
Definition: builder.h:834
constexpr NestedJsonObject & Add(std::string_view key, const T &value)
Adds a key-value pair to the nested object.
Definition: builder.h:817
constexpr NestedJsonObject AddNestedObject(std::string_view key)
Adds a nested object to the nested object.
Definition: builder.h:811
constexpr void clear_status()
Resets status() and last_status().
Definition: builder.h:344
constexpr JsonObject & Add(std::string_view key, const T &value)
Definition: builder.h:849
static constexpr size_t MinBufferSize()
JsonBuilder requires at least 5 characters in its buffer.
Definition: builder.h:279
constexpr JsonValue & StartValue()
Definition: builder.h:352
constexpr bool IsObject() const
True if the top-level JSON entity is an object.
Definition: builder.h:301
The Pigweed namespace.
Definition: alignment.h:27
constexpr Status OkStatus()
Definition: status.h:235
Definition: builder.h:708
Definition: builder.h:710