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();
150 template <
typename T>
168 [[nodiscard]]
constexpr bool IsValue()
const;
169 [[nodiscard]]
constexpr bool IsArray()
const;
170 [[nodiscard]]
constexpr bool IsObject()
const;
172 constexpr operator std::string_view()
const;
173 constexpr const char* data()
const;
174 constexpr size_t size()
const;
175 constexpr size_t max_size()
const;
177 [[nodiscard]]
constexpr bool ok()
const;
178 constexpr Status status()
const;
179 constexpr Status last_status()
const;
180 constexpr void clear();
181 constexpr void clear_status();
187 template <
typename T>
198 template <
typename Iterable>
203 template <
typename T,
size_t kSize>
221 [[nodiscard]]
constexpr bool IsValue()
const;
222 [[nodiscard]]
constexpr bool IsArray()
const;
223 [[nodiscard]]
constexpr bool IsObject()
const;
225 constexpr operator std::string_view()
const;
226 constexpr const char* data()
const;
227 constexpr size_t size()
const;
228 constexpr size_t max_size()
const;
230 [[nodiscard]]
constexpr bool ok()
const;
231 constexpr Status status()
const;
232 constexpr Status last_status()
const;
233 constexpr void clear();
234 constexpr void clear_status();
244 template <
typename T>
245 constexpr JsonObject&
Add(std::string_view key,
const T& value);
247 template <
typename T>
248 constexpr JsonObject&
Add(std::nullptr_t,
const T& value) =
delete;
274 :
JsonBuilder(buffer, buffer_size, Uninitialized{}) {
280 [[nodiscard]]
constexpr bool IsValue()
const {
285 [[nodiscard]]
constexpr bool IsArray()
const {
return buffer_[0] ==
'['; }
288 [[nodiscard]]
constexpr bool IsObject()
const {
return buffer_[0] ==
'{'; }
291 constexpr operator std::string_view()
const {
return {
data(),
size()}; }
294 constexpr const char*
data()
const {
return buffer_; }
297 constexpr size_t size()
const {
return json_size_; }
300 constexpr size_t max_size()
const {
return max_size_; }
303 [[nodiscard]]
constexpr bool ok()
const {
return status().
ok(); }
322 constexpr void clear() { JsonValueClear(); }
328 template <
typename T>
368 enum class Uninitialized {};
371 constexpr JsonBuilder(
char* buffer,
size_t buffer_size, Uninitialized)
373 max_size_(buffer_size - 1),
379 constexpr void MakeNull() {
388 constexpr void set_json_size(
size_t json_size) { json_size_ = json_size; }
396 friend class JsonValue;
397 friend class JsonArray;
398 friend class JsonObject;
400 friend class NestedJsonArray;
401 friend class NestedJsonObject;
403 constexpr size_t remaining()
const {
return max_size() -
size(); }
406 constexpr void update_status(Status new_status);
410 constexpr void JsonValueClear() {
415 constexpr void JsonArrayClear() {
420 constexpr void JsonObjectClear() {
425 template <
typename T>
426 constexpr Status JsonValueSet(
const T& value);
428 template <
typename T>
429 constexpr JsonArray& JsonArrayAppend(
const T& value);
431 template <
typename Iterator>
432 constexpr JsonArray& JsonArrayExtend(Iterator begin, Iterator end);
434 template <
typename T>
435 constexpr JsonObject& JsonObjectAdd(std::string_view key,
const T& value);
437 [[nodiscard]]
constexpr bool JsonArrayAddElement();
440 [[nodiscard]]
constexpr bool JsonObjectAddKey(std::string_view key);
442 constexpr size_t NestedJsonOffset(
const json_impl::Nesting& nesting)
const {
445 return json_size_ - 3 - nesting.depth();
448 constexpr json_impl::Nesting::Type type()
const {
449 return IsArray() ? json_impl::Nesting::kArray : json_impl::Nesting::kObject;
452 constexpr json_impl::NestedJson JsonArrayAppendNested(
453 const char (&open_close)[2],
const json_impl::Nesting& nesting);
455 constexpr json_impl::NestedJson JsonObjectAddNested(
456 std::string_view key,
457 const char (&open_close)[2],
458 const json_impl::Nesting& nesting);
462 constexpr void AddNestedStart(
const json_impl::Nesting& nesting);
463 constexpr void AddNestedFinish(
const json_impl::Nesting& nesting);
465 template <
typename T>
466 constexpr void NestedJsonArrayAppend(
const T& value,
467 const json_impl::Nesting& nesting);
469 template <
typename T>
470 constexpr void NestedJsonObjectAdd(std::string_view key,
472 const json_impl::Nesting& nesting);
475 constexpr Status HandleSet(StatusWithSize written);
479 constexpr void HandleAdd(StatusWithSize written,
480 size_t starting_size,
483 constexpr void MakeEmpty(
char open,
char close) {
498 uint8_t last_status_;
503template <
size_t kMaxSize>
508 :
JsonBuilder(static_buffer_,
sizeof(static_buffer_), Uninitialized{}),
513 template <
typename T>
514 static constexpr JsonBuffer Value(
const T& initial_value) {
526 template <
size_t kOtherSize>
536 template <
size_t kOtherSize>
542 static constexpr size_t max_size() {
return kMaxSize; }
546 "JsonBuffers require at least 4 bytes");
548 template <
size_t kOtherSize>
550 static_assert(kOtherSize <= kMaxSize,
551 "A JsonBuffer cannot be copied into a smaller buffer");
555 constexpr void CopyFrom(
const JsonBuilder& other) {
556 for (
size_t i = 0; i < other.
size() + 1 ; ++i) {
557 static_buffer_[i] = other.
data()[i];
559 JsonBuilder::set_json_size(other.
size());
563 char static_buffer_[kMaxSize + 1];
570inline constexpr char kArray[2] = {
'[',
']'};
571inline constexpr char kObject[2] = {
'{',
'}'};
573constexpr StatusWithSize WriteString(std::string_view value,
576 if (value.size() + 1 > remaining) {
577 return StatusWithSize::ResourceExhausted();
579 for (
char c : value) {
583 return StatusWithSize(value.size());
586constexpr char NibbleToHex(uint8_t nibble) {
587 return nibble + (nibble < 10 ?
'0' : (
'a' - 10));
603constexpr int EscapedStringCopy(
char* destination,
605 std::string_view source) {
606 int destination_index = 0;
608 for (
char source_char : source) {
609 if (destination_index >= copy_limit) {
613 char escaped_character =
'\0';
615 if (source_char >=
'\b' && source_char <=
'\r' && source_char !=
'\v') {
616 constexpr char kControlChars[] = {
'b',
't',
'n',
'?',
'f',
'r'};
617 escaped_character = kControlChars[source_char -
'\b'];
618 }
else if (source_char ==
'"' || source_char ==
'\\') {
619 escaped_character = source_char;
620 }
else if (source_char >=
' ' && source_char <=
'~') {
622 destination[destination_index++] = source_char;
627 if (copy_limit - destination_index < 6) {
631 destination[destination_index++] =
'\\';
632 destination[destination_index++] =
'u';
633 destination[destination_index++] =
'0';
634 destination[destination_index++] =
'0';
635 destination[destination_index++] = NibbleToHex((source_char >> 4) & 0x0f);
636 destination[destination_index++] = NibbleToHex(source_char & 0x0f);
641 if (copy_limit - destination_index < 2) {
645 destination[destination_index++] =
'\\';
646 destination[destination_index++] = escaped_character;
648 return destination_index;
653constexpr StatusWithSize WriteQuotedString(std::string_view value,
655 size_t buffer_size) {
656 constexpr size_t kOverhead = 2 + 1 ;
657 if (value.size() + kOverhead > buffer_size) {
658 return StatusWithSize::ResourceExhausted();
663 EscapedStringCopy(buffer + 1 , buffer_size - kOverhead, value);
665 return StatusWithSize::ResourceExhausted();
669 buffer[written + 1] =
'"';
670 buffer[written + 2] =
'\0';
671 return StatusWithSize(written + 2);
674constexpr StatusWithSize WriteCharPointer(
const char* ptr,
676 size_t buffer_size) {
677 if (ptr ==
nullptr) {
678 return WriteString(
"null", buffer, buffer_size);
680 return WriteQuotedString(ptr, buffer, buffer_size);
684inline constexpr bool kIsJson =
685 std::is_base_of_v<JsonValue, T> || std::is_base_of_v<JsonArray, T> ||
686 std::is_base_of_v<JsonObject, T>;
692 const char (&open_close)[2];
699 if constexpr (kIsJson<T>) {
700 return WriteString(value, buffer, remaining);
701 }
else if constexpr (std::is_same_v<T, LiteralChars>) {
703 std::string_view(value.open_close, 2), buffer, remaining);
704 }
else if constexpr (std::is_null_pointer_v<T> ||
705 std::is_same_v<T, char*> ||
706 std::is_same_v<T, const char*>) {
707 return WriteCharPointer(value, buffer, remaining);
708 }
else if constexpr (std::is_convertible_v<T, std::string_view>) {
709 return WriteQuotedString(value, buffer, remaining);
710 }
else if constexpr (std::is_floating_point_v<T>) {
711 return string::FloatAsIntToString(value, {buffer, remaining});
712 }
else if constexpr (std::is_same_v<T, bool>) {
713 return WriteString(value ?
"true" :
"false", buffer, remaining);
714 }
else if constexpr (std::is_integral_v<T>) {
715 return string::IntToString(value, {buffer, remaining});
717 static_assert(InvalidJsonType<T>(),
718 "JSON values may only be numbers, strings, JSON arrays, JSON "
720 return StatusWithSize::Internal();
729#define PW_JSON_COMMON_INTERFACE_IMPL(name) \
730 constexpr bool name::IsValue() const { \
731 return static_cast<const JsonBuilder*>(this)->IsValue(); \
733 constexpr bool name::IsArray() const { \
734 return static_cast<const JsonBuilder*>(this)->IsArray(); \
736 constexpr bool name::IsObject() const { \
737 return static_cast<const JsonBuilder*>(this)->IsObject(); \
739 constexpr name::operator std::string_view() const { \
740 return static_cast<const JsonBuilder*>(this)->operator std::string_view(); \
742 constexpr const char* name::data() const { \
743 return static_cast<const JsonBuilder*>(this)->data(); \
745 constexpr size_t name::size() const { \
746 return static_cast<const JsonBuilder*>(this)->size(); \
748 constexpr size_t name::max_size() const { \
749 return static_cast<const JsonBuilder*>(this)->max_size(); \
751 constexpr bool name::ok() const { \
752 return static_cast<const JsonBuilder*>(this)->ok(); \
754 constexpr Status name::status() const { \
755 return static_cast<const JsonBuilder*>(this)->status(); \
757 constexpr Status name::last_status() const { \
758 return static_cast<const JsonBuilder*>(this)->last_status(); \
760 constexpr void name::clear() { \
761 static_cast<JsonBuilder*>(this)->name##Clear(); \
763 constexpr void name::clear_status() { \
764 static_cast<JsonBuilder*>(this)->clear_status(); \
768PW_JSON_COMMON_INTERFACE_IMPL(JsonValue);
769PW_JSON_COMMON_INTERFACE_IMPL(JsonArray);
770PW_JSON_COMMON_INTERFACE_IMPL(JsonObject);
772#undef PW_JSON_COMMON_INTERFACE_IMPL
776 json_.builder().NestedJsonArrayAppend(value, json_.nesting());
780 return json_.builder().JsonArrayAppendNested(json_impl::kArray,
784 return json_.builder().JsonArrayAppendNested(json_impl::kObject,
788 std::string_view key) {
789 return json_.builder().JsonObjectAddNested(
790 key, json_impl::kArray, json_.nesting());
793 std::string_view key) {
794 return json_.builder().JsonObjectAddNested(
795 key, json_impl::kObject, json_.nesting());
800 json_.builder().NestedJsonObjectAdd(key, value, json_.nesting());
805 return static_cast<JsonBuilder*
>(
this)->JsonValueSet(value);
809 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppend(value);
812 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
813 json_impl::kArray, {});
816 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
817 json_impl::kObject, {});
819template <
typename Iterable>
821 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
822 std::cend(iterable));
824template <
typename T,
size_t kSize>
826 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
827 std::cend(iterable));
831 return static_cast<JsonBuilder*
>(
this)->JsonObjectAdd(key, value);
833constexpr NestedJsonArray JsonObject::AddNestedArray(std::string_view key) {
834 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
835 key, json_impl::kArray, {});
837constexpr NestedJsonObject JsonObject::AddNestedObject(std::string_view key) {
838 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
839 key, json_impl::kObject, {});
846 return HandleSet(json_impl::SerializeJson(value, buffer_, max_size_ + 1));
849constexpr void JsonBuilder::update_status(
Status new_status) {
850 last_status_ = new_status.
code();
852 status_ = new_status.
code();
857constexpr Status JsonBuilder::JsonValueSet(
const T& value) {
858 if constexpr (json_impl::kIsJson<T>) {
859 PW_ASSERT(
this != &value);
860 PW_ASSERT(value.IsValue());
866constexpr JsonArray& JsonBuilder::JsonArrayAppend(
const T& value) {
867 if constexpr (json_impl::kIsJson<T>) {
868 PW_ASSERT(
this != &value);
871 const size_t starting_size =
size();
872 if (JsonArrayAddElement()) {
875 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
882template <
typename Iterator>
883constexpr JsonArray& JsonBuilder::JsonArrayExtend(Iterator begin,
885 const size_t starting_size =
size();
887 for (Iterator cur = begin; cur != end; ++cur) {
890 json_size_ = starting_size;
891 buffer_[
size() - 1] =
']';
892 buffer_[
size()] =
'\0';
900constexpr JsonObject& JsonBuilder::JsonObjectAdd(std::string_view key,
902 if constexpr (json_impl::kIsJson<T>) {
903 PW_ASSERT(
this != &value);
906 const size_t starting_size =
size();
907 if (JsonObjectAddKey(key)) {
910 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
917constexpr bool JsonBuilder::JsonArrayAddElement() {
930 buffer_[json_size_ - 1] =
',';
931 buffer_[json_size_++] =
' ';
937constexpr bool JsonBuilder::JsonObjectAddKey(std::string_view key) {
952 buffer_[json_size_ - 1] =
',';
953 buffer_[json_size_++] =
' ';
958 json_impl::WriteQuotedString(key, &buffer_[json_size_], remaining() - 3);
963 json_size_ += written.size();
964 buffer_[json_size_++] =
':';
965 buffer_[json_size_++] =
' ';
969constexpr json_impl::NestedJson JsonBuilder::JsonArrayAppendNested(
970 const char (&open_close)[2],
const json_impl::Nesting& nesting) {
971 AddNestedStart(nesting);
972 json_impl::Nesting::Type nesting_within = type();
973 JsonArrayAppend(json_impl::LiteralChars{open_close});
974 AddNestedFinish(nesting);
975 return json_impl::NestedJson(
978 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
979 : json_impl::Nesting());
982constexpr json_impl::NestedJson JsonBuilder::JsonObjectAddNested(
983 std::string_view key,
984 const char (&open_close)[2],
985 const json_impl::Nesting& nesting) {
986 AddNestedStart(nesting);
987 json_impl::Nesting::Type nesting_within = type();
988 JsonObjectAdd(key, json_impl::LiteralChars{open_close});
989 AddNestedFinish(nesting);
990 return json_impl::NestedJson(
993 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
994 : json_impl::Nesting());
997constexpr void JsonBuilder::AddNestedStart(
const json_impl::Nesting& nesting) {
1001 json_size_ >= nesting.offset() + nesting.depth() + 2 );
1003 buffer_[json_size_ - nesting.depth() - 1] ==
1004 buffer_[nesting.offset()] + 2 );
1005 nesting.CheckNesting(&buffer_[json_size_ - nesting.depth()]);
1007 buffer_ += nesting.offset();
1008 json_size_ -= nesting.offset() + nesting.depth();
1009 max_size_ -= nesting.offset() + nesting.depth();
1012constexpr void JsonBuilder::AddNestedFinish(
const json_impl::Nesting& nesting) {
1013 buffer_ -= nesting.offset();
1014 max_size_ += nesting.offset() + nesting.depth();
1016 json_size_ += nesting.offset();
1017 nesting.Terminate(&buffer_[json_size_]);
1018 json_size_ += nesting.depth();
1021template <
typename T>
1022constexpr void JsonBuilder::NestedJsonArrayAppend(
1023 const T& value,
const json_impl::Nesting& nesting) {
1024 AddNestedStart(nesting);
1025 JsonArrayAppend(value);
1026 AddNestedFinish(nesting);
1029template <
typename T>
1030constexpr void JsonBuilder::NestedJsonObjectAdd(
1031 std::string_view key,
const T& value,
const json_impl::Nesting& nesting) {
1032 AddNestedStart(nesting);
1033 JsonObjectAdd(key, value);
1034 AddNestedFinish(nesting);
1037constexpr Status JsonBuilder::HandleSet(StatusWithSize written) {
1039 json_size_ = written.size();
1043 set_statuses(written.status());
1047constexpr void JsonBuilder::HandleAdd(StatusWithSize written,
1048 size_t starting_size,
1050 update_status(written.status());
1052 json_size_ += written.size();
1054 json_size_ = starting_size - 1;
1057 buffer_[json_size_++] = terminator;
1058 buffer_[json_size_] =
'\0';
Definition: builder.h:162
Definition: builder.h:504
Definition: builder.h:263
Definition: builder.h:215
Definition: builder.h:119
constexpr Code code() const
Definition: status.h:341
constexpr bool ok() const
Definition: status.h:346
static constexpr Status ResourceExhausted()
Definition: status.h:230
Definition: status_with_size.h:51
Definition: span_impl.h:235
constexpr Status status() const
Definition: builder.h:313
constexpr bool IsArray() const
True if the top-level JSON entity is an array.
Definition: builder.h:285
constexpr JsonBuilder(char *buffer, size_t buffer_size)
Initializes to the value null. buffer_size must be at least 5.
Definition: builder.h:273
constexpr JsonObject & StartObject()
Definition: builder.h:362
constexpr size_t max_size() const
The maximum size of the JSON string, excluding the null terminator.
Definition: builder.h:300
constexpr bool IsValue() const
True if the top-level JSON entity is a simple value (not array or object).
Definition: builder.h:280
constexpr Status last_status() const
Definition: builder.h:317
constexpr NestedJsonArray AddNestedArray(std::string_view key)
Adds a nested array to the nested object.
Definition: builder.h:787
constexpr JsonBuilder(span< char > buffer)
Initializes to the value null. buffer.size() must be at least 5.
Definition: builder.h:269
constexpr NestedJsonObject AppendNestedObject()
Appends a new nested object to this nested array.
Definition: builder.h:783
constexpr const char * data() const
Pointer to the serialized JSON, which is always a null-terminated string.
Definition: builder.h:294
constexpr JsonArray & Append(const T &value)
Definition: builder.h:808
constexpr Status Set(const T &value)
Definition: builder.h:804
constexpr NestedJsonArray AppendNestedArray()
Appends a new nested array to this nested array.
Definition: builder.h:779
constexpr Status SetValue(const T &value)
Clears the JSON and sets it to a single JSON value (see JsonValue::Set).
Definition: builder.h:845
constexpr NestedJsonArray & Append(const T &value)
Appends to the nested array.
Definition: builder.h:775
constexpr size_t size() const
The current size of the JSON string, excluding the null terminator.
Definition: builder.h:297
constexpr bool ok() const
True if.
Definition: builder.h:303
constexpr void clear()
Sets the JSON null and clears the status.
Definition: builder.h:322
constexpr JsonArray & Extend(const Iterable &iterable)
Definition: builder.h:820
constexpr NestedJsonArray AppendNestedArray()
Appends a nested array to this array.
Definition: builder.h:811
constexpr JsonArray & StartArray()
Definition: builder.h:347
constexpr NestedJsonObject AppendNestedObject()
Appends a nested object to this array.
Definition: builder.h:815
constexpr NestedJsonObject & Add(std::string_view key, const T &value)
Adds a key-value pair to the nested object.
Definition: builder.h:798
constexpr NestedJsonObject AddNestedObject(std::string_view key)
Adds a nested object to the nested object.
Definition: builder.h:792
constexpr void clear_status()
Resets status() and last_status().
Definition: builder.h:325
constexpr JsonObject & Add(std::string_view key, const T &value)
Definition: builder.h:830
static constexpr size_t MinBufferSize()
JsonBuilder requires at least 5 characters in its buffer.
Definition: builder.h:266
constexpr JsonValue & StartValue()
Definition: builder.h:333
constexpr bool IsObject() const
True if the top-level JSON entity is an object.
Definition: builder.h:288
pw_Status
C API for status codes. In C++, use the pw::Status class instead.
Definition: status.h:40
constexpr Status OkStatus()
Definition: status.h:450
The Pigweed namespace.
Definition: alignment.h:27
Definition: builder.h:689
Definition: builder.h:691