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"
74 : json_(std::move(nested)) {}
76 json_impl::NestedJson json_;
108 : json_(std::move(nested)) {}
110 json_impl::NestedJson json_;
122 [[nodiscard]]
constexpr bool IsValue()
const;
123 [[nodiscard]]
constexpr bool IsArray()
const;
124 [[nodiscard]]
constexpr bool IsObject()
const;
126 constexpr operator std::string_view()
const;
127 constexpr const char* data()
const;
128 constexpr size_t size()
const;
129 constexpr size_t max_size()
const;
131 [[nodiscard]]
constexpr bool ok()
const;
132 constexpr Status status()
const;
133 constexpr Status last_status()
const;
134 constexpr void clear();
135 constexpr void clear_status();
147 template <
typename T>
165 [[nodiscard]]
constexpr bool IsValue()
const;
166 [[nodiscard]]
constexpr bool IsArray()
const;
167 [[nodiscard]]
constexpr bool IsObject()
const;
169 constexpr operator std::string_view()
const;
170 constexpr const char* data()
const;
171 constexpr size_t size()
const;
172 constexpr size_t max_size()
const;
174 [[nodiscard]]
constexpr bool ok()
const;
175 constexpr Status status()
const;
176 constexpr Status last_status()
const;
177 constexpr void clear();
178 constexpr void clear_status();
184 template <
typename T>
195 template <
typename Iterable>
200 template <
typename T,
size_t kSize>
218 [[nodiscard]]
constexpr bool IsValue()
const;
219 [[nodiscard]]
constexpr bool IsArray()
const;
220 [[nodiscard]]
constexpr bool IsObject()
const;
222 constexpr operator std::string_view()
const;
223 constexpr const char* data()
const;
224 constexpr size_t size()
const;
225 constexpr size_t max_size()
const;
227 [[nodiscard]]
constexpr bool ok()
const;
228 constexpr Status status()
const;
229 constexpr Status last_status()
const;
230 constexpr void clear();
231 constexpr void clear_status();
241 template <
typename T>
242 constexpr JsonObject&
Add(std::string_view key,
const T& value);
244 template <
typename T>
245 constexpr JsonObject&
Add(std::nullptr_t,
const T& value) =
delete;
271 :
JsonBuilder(buffer, buffer_size, Uninitialized{}) {
277 [[nodiscard]]
constexpr bool IsValue()
const {
282 [[nodiscard]]
constexpr bool IsArray()
const {
return buffer_[0] ==
'['; }
285 [[nodiscard]]
constexpr bool IsObject()
const {
return buffer_[0] ==
'{'; }
288 constexpr operator std::string_view()
const {
return {
data(),
size()}; }
291 constexpr const char*
data()
const {
return buffer_; }
294 constexpr size_t size()
const {
return json_size_; }
297 constexpr size_t max_size()
const {
return max_size_; }
300 [[nodiscard]]
constexpr bool ok()
const {
return status().
ok(); }
319 constexpr void clear() { JsonValueClear(); }
325 template <
typename T>
365 enum class Uninitialized {};
368 constexpr JsonBuilder(
char* buffer,
size_t buffer_size, Uninitialized)
370 max_size_(buffer_size - 1),
376 constexpr void MakeNull() {
385 constexpr void set_json_size(
size_t json_size) { json_size_ = json_size; }
393 friend class JsonValue;
394 friend class JsonArray;
395 friend class JsonObject;
397 friend class NestedJsonArray;
398 friend class NestedJsonObject;
400 constexpr size_t remaining()
const {
return max_size() -
size(); }
403 constexpr void update_status(Status new_status);
407 constexpr void JsonValueClear() {
412 constexpr void JsonArrayClear() {
417 constexpr void JsonObjectClear() {
422 template <
typename T>
423 constexpr Status JsonValueSet(
const T& value);
425 template <
typename T>
426 constexpr JsonArray& JsonArrayAppend(
const T& value);
428 template <
typename Iterator>
429 constexpr JsonArray& JsonArrayExtend(Iterator begin, Iterator end);
431 template <
typename T>
432 constexpr JsonObject& JsonObjectAdd(std::string_view key,
const T& value);
434 [[nodiscard]]
constexpr bool JsonArrayAddElement();
437 [[nodiscard]]
constexpr bool JsonObjectAddKey(std::string_view key);
439 constexpr size_t NestedJsonOffset(
const json_impl::Nesting& nesting)
const {
442 return json_size_ - 3 - nesting.depth();
445 constexpr json_impl::Nesting::Type type()
const {
446 return IsArray() ? json_impl::Nesting::kArray : json_impl::Nesting::kObject;
449 constexpr json_impl::NestedJson JsonArrayAppendNested(
450 const char (&open_close)[2],
const json_impl::Nesting& nesting);
452 constexpr json_impl::NestedJson JsonObjectAddNested(
453 std::string_view key,
454 const char (&open_close)[2],
455 const json_impl::Nesting& nesting);
459 constexpr void AddNestedStart(
const json_impl::Nesting& nesting);
460 constexpr void AddNestedFinish(
const json_impl::Nesting& nesting);
462 template <
typename T>
463 constexpr void NestedJsonArrayAppend(
const T& value,
464 const json_impl::Nesting& nesting);
466 template <
typename T>
467 constexpr void NestedJsonObjectAdd(std::string_view key,
469 const json_impl::Nesting& nesting);
472 constexpr Status HandleSet(StatusWithSize written);
476 constexpr void HandleAdd(StatusWithSize written,
477 size_t starting_size,
480 constexpr void MakeEmpty(
char open,
char close) {
495 uint8_t last_status_;
500template <
size_t kMaxSize>
505 :
JsonBuilder(static_buffer_,
sizeof(static_buffer_), Uninitialized{}),
510 template <
typename T>
511 static constexpr JsonBuffer Value(
const T& initial_value) {
523 template <
size_t kOtherSize>
533 template <
size_t kOtherSize>
539 static constexpr size_t max_size() {
return kMaxSize; }
543 "JsonBuffers require at least 4 bytes");
545 template <
size_t kOtherSize>
547 static_assert(kOtherSize <= kMaxSize,
548 "A JsonBuffer cannot be copied into a smaller buffer");
552 constexpr void CopyFrom(
const JsonBuilder& other) {
553 for (
size_t i = 0; i < other.
size() + 1 ; ++i) {
554 static_buffer_[i] = other.
data()[i];
556 JsonBuilder::set_json_size(other.
size());
560 char static_buffer_[kMaxSize + 1];
567inline constexpr char kArray[2] = {
'[',
']'};
568inline constexpr char kObject[2] = {
'{',
'}'};
570constexpr StatusWithSize WriteString(std::string_view value,
573 if (value.size() + 1 > remaining) {
574 return StatusWithSize::ResourceExhausted();
576 for (
char c : value) {
580 return StatusWithSize(value.size());
583constexpr char NibbleToHex(uint8_t nibble) {
584 return nibble + (nibble < 10 ?
'0' : (
'a' - 10));
600constexpr int EscapedStringCopy(
char* destination,
602 std::string_view source) {
603 int destination_index = 0;
605 for (
char source_char : source) {
606 if (destination_index >= copy_limit) {
610 char escaped_character =
'\0';
612 if (source_char >=
'\b' && source_char <=
'\r' && source_char !=
'\v') {
613 constexpr char kControlChars[] = {
'b',
't',
'n',
'?',
'f',
'r'};
614 escaped_character = kControlChars[source_char -
'\b'];
615 }
else if (source_char ==
'"' || source_char ==
'\\') {
616 escaped_character = source_char;
617 }
else if (source_char >=
' ' && source_char <=
'~') {
619 destination[destination_index++] = source_char;
624 if (copy_limit - destination_index < 6) {
628 destination[destination_index++] =
'\\';
629 destination[destination_index++] =
'u';
630 destination[destination_index++] =
'0';
631 destination[destination_index++] =
'0';
632 destination[destination_index++] = NibbleToHex((source_char >> 4) & 0x0f);
633 destination[destination_index++] = NibbleToHex(source_char & 0x0f);
638 if (copy_limit - destination_index < 2) {
642 destination[destination_index++] =
'\\';
643 destination[destination_index++] = escaped_character;
645 return destination_index;
650constexpr StatusWithSize WriteQuotedString(std::string_view value,
652 size_t buffer_size) {
653 constexpr size_t kOverhead = 2 + 1 ;
654 if (value.size() + kOverhead > buffer_size) {
655 return StatusWithSize::ResourceExhausted();
659 const int written = EscapedStringCopy(
660 buffer + 1 ,
static_cast<int>(buffer_size - kOverhead), value);
662 return StatusWithSize::ResourceExhausted();
666 buffer[written + 1] =
'"';
667 buffer[written + 2] =
'\0';
668 return StatusWithSize(written + 2);
671constexpr StatusWithSize WriteCharPointer(
const char* ptr,
673 size_t buffer_size) {
674 if (ptr ==
nullptr) {
675 return WriteString(
"null", buffer, buffer_size);
677 return WriteQuotedString(ptr, buffer, buffer_size);
681inline constexpr bool kIsJson =
682 std::is_base_of_v<JsonValue, T> || std::is_base_of_v<JsonArray, T> ||
683 std::is_base_of_v<JsonObject, T>;
689 const char (&open_close)[2];
696 if constexpr (kIsJson<T>) {
697 return WriteString(value, buffer, remaining);
698 }
else if constexpr (std::is_same_v<T, LiteralChars>) {
700 std::string_view(value.open_close, 2), buffer, remaining);
701 }
else if constexpr (std::is_null_pointer_v<T> ||
702 std::is_same_v<T, char*> ||
703 std::is_same_v<T, const char*>) {
704 return WriteCharPointer(value, buffer, remaining);
705 }
else if constexpr (std::is_convertible_v<T, std::string_view>) {
706 return WriteQuotedString(value, buffer, remaining);
707 }
else if constexpr (std::is_floating_point_v<T>) {
708 return string::FloatAsIntToString(
static_cast<float>(value),
709 {buffer, remaining});
710 }
else if constexpr (std::is_same_v<T, bool>) {
711 return WriteString(value ?
"true" :
"false", buffer, remaining);
712 }
else if constexpr (std::is_integral_v<T>) {
713 return string::IntToString(value, {buffer, remaining});
715 static_assert(InvalidJsonType<T>(),
716 "JSON values may only be numbers, strings, JSON arrays, JSON "
718 return StatusWithSize::Internal();
727#define PW_JSON_COMMON_INTERFACE_IMPL(name) \
728 constexpr bool name::IsValue() const { \
729 return static_cast<const JsonBuilder*>(this)->IsValue(); \
731 constexpr bool name::IsArray() const { \
732 return static_cast<const JsonBuilder*>(this)->IsArray(); \
734 constexpr bool name::IsObject() const { \
735 return static_cast<const JsonBuilder*>(this)->IsObject(); \
737 constexpr name::operator std::string_view() const { \
738 return static_cast<const JsonBuilder*>(this)->operator std::string_view(); \
740 constexpr const char* name::data() const { \
741 return static_cast<const JsonBuilder*>(this)->data(); \
743 constexpr size_t name::size() const { \
744 return static_cast<const JsonBuilder*>(this)->size(); \
746 constexpr size_t name::max_size() const { \
747 return static_cast<const JsonBuilder*>(this)->max_size(); \
749 constexpr bool name::ok() const { \
750 return static_cast<const JsonBuilder*>(this)->ok(); \
752 constexpr Status name::status() const { \
753 return static_cast<const JsonBuilder*>(this)->status(); \
755 constexpr Status name::last_status() const { \
756 return static_cast<const JsonBuilder*>(this)->last_status(); \
758 constexpr void name::clear() { \
759 static_cast<JsonBuilder*>(this)->name##Clear(); \
761 constexpr void name::clear_status() { \
762 static_cast<JsonBuilder*>(this)->clear_status(); \
766PW_JSON_COMMON_INTERFACE_IMPL(JsonValue);
767PW_JSON_COMMON_INTERFACE_IMPL(JsonArray);
768PW_JSON_COMMON_INTERFACE_IMPL(JsonObject);
770#undef PW_JSON_COMMON_INTERFACE_IMPL
774 json_.builder().NestedJsonArrayAppend(value, json_.nesting());
778 return json_.builder().JsonArrayAppendNested(json_impl::kArray,
782 return json_.builder().JsonArrayAppendNested(json_impl::kObject,
786 std::string_view key) {
787 return json_.builder().JsonObjectAddNested(
788 key, json_impl::kArray, json_.nesting());
791 std::string_view key) {
792 return json_.builder().JsonObjectAddNested(
793 key, json_impl::kObject, json_.nesting());
798 json_.builder().NestedJsonObjectAdd(key, value, json_.nesting());
803 return static_cast<JsonBuilder*
>(
this)->JsonValueSet(value);
807 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppend(value);
810 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
811 json_impl::kArray, {});
814 return static_cast<JsonBuilder*
>(
this)->JsonArrayAppendNested(
815 json_impl::kObject, {});
817template <
typename Iterable>
819 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
820 std::cend(iterable));
822template <
typename T,
size_t kSize>
824 return static_cast<JsonBuilder*
>(
this)->JsonArrayExtend(std::cbegin(iterable),
825 std::cend(iterable));
829 return static_cast<JsonBuilder*
>(
this)->JsonObjectAdd(key, value);
831constexpr NestedJsonArray JsonObject::AddNestedArray(std::string_view key) {
832 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
833 key, json_impl::kArray, {});
835constexpr NestedJsonObject JsonObject::AddNestedObject(std::string_view key) {
836 return static_cast<JsonBuilder*
>(
this)->JsonObjectAddNested(
837 key, json_impl::kObject, {});
844 return HandleSet(json_impl::SerializeJson(value, buffer_, max_size_ + 1));
847constexpr void JsonBuilder::update_status(
Status new_status) {
848 last_status_ = new_status.
code();
850 status_ = new_status.
code();
855constexpr Status JsonBuilder::JsonValueSet(
const T& value) {
856 if constexpr (json_impl::kIsJson<T>) {
857 PW_ASSERT(
this != &value);
858 PW_ASSERT(value.IsValue());
864constexpr JsonArray& JsonBuilder::JsonArrayAppend(
const T& value) {
865 if constexpr (json_impl::kIsJson<T>) {
866 PW_ASSERT(
this != &value);
869 const size_t starting_size =
size();
870 if (JsonArrayAddElement()) {
873 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
880template <
typename Iterator>
881constexpr JsonArray& JsonBuilder::JsonArrayExtend(Iterator begin,
883 const size_t starting_size =
size();
885 for (Iterator cur = begin; cur != end; ++cur) {
888 json_size_ = starting_size;
889 buffer_[
size() - 1] =
']';
890 buffer_[
size()] =
'\0';
898constexpr JsonObject& JsonBuilder::JsonObjectAdd(std::string_view key,
900 if constexpr (json_impl::kIsJson<T>) {
901 PW_ASSERT(
this != &value);
904 const size_t starting_size =
size();
905 if (JsonObjectAddKey(key)) {
908 HandleAdd(json_impl::SerializeJson(value, &buffer_[
size()], remaining()),
915constexpr bool JsonBuilder::JsonArrayAddElement() {
928 buffer_[json_size_ - 1] =
',';
929 buffer_[json_size_++] =
' ';
935constexpr bool JsonBuilder::JsonObjectAddKey(std::string_view key) {
950 buffer_[json_size_ - 1] =
',';
951 buffer_[json_size_++] =
' ';
956 json_impl::WriteQuotedString(key, &buffer_[json_size_], remaining() - 3);
961 json_size_ += written.size();
962 buffer_[json_size_++] =
':';
963 buffer_[json_size_++] =
' ';
967constexpr json_impl::NestedJson JsonBuilder::JsonArrayAppendNested(
968 const char (&open_close)[2],
const json_impl::Nesting& nesting) {
969 AddNestedStart(nesting);
970 json_impl::Nesting::Type nesting_within = type();
971 JsonArrayAppend(json_impl::LiteralChars{open_close});
972 AddNestedFinish(nesting);
973 return json_impl::NestedJson(
976 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
977 : json_impl::Nesting());
980constexpr json_impl::NestedJson JsonBuilder::JsonObjectAddNested(
981 std::string_view key,
982 const char (&open_close)[2],
983 const json_impl::Nesting& nesting) {
984 AddNestedStart(nesting);
985 json_impl::Nesting::Type nesting_within = type();
986 JsonObjectAdd(key, json_impl::LiteralChars{open_close});
987 AddNestedFinish(nesting);
988 return json_impl::NestedJson(
991 ? nesting.Nest(NestedJsonOffset(nesting), nesting_within)
992 : json_impl::Nesting());
995constexpr void JsonBuilder::AddNestedStart(
const json_impl::Nesting& nesting) {
999 json_size_ >= nesting.offset() + nesting.depth() + 2 );
1001 buffer_[json_size_ - nesting.depth() - 1] ==
1002 buffer_[nesting.offset()] + 2 );
1003 nesting.CheckNesting(&buffer_[json_size_ - nesting.depth()]);
1005 buffer_ += nesting.offset();
1006 json_size_ -= nesting.offset() + nesting.depth();
1007 max_size_ -= nesting.offset() + nesting.depth();
1010constexpr void JsonBuilder::AddNestedFinish(
const json_impl::Nesting& nesting) {
1011 buffer_ -= nesting.offset();
1012 max_size_ += nesting.offset() + nesting.depth();
1014 json_size_ += nesting.offset();
1015 nesting.Terminate(&buffer_[json_size_]);
1016 json_size_ += nesting.depth();
1019template <
typename T>
1020constexpr void JsonBuilder::NestedJsonArrayAppend(
1021 const T& value,
const json_impl::Nesting& nesting) {
1022 AddNestedStart(nesting);
1023 JsonArrayAppend(value);
1024 AddNestedFinish(nesting);
1027template <
typename T>
1028constexpr void JsonBuilder::NestedJsonObjectAdd(
1029 std::string_view key,
const T& value,
const json_impl::Nesting& nesting) {
1030 AddNestedStart(nesting);
1031 JsonObjectAdd(key, value);
1032 AddNestedFinish(nesting);
1035constexpr Status JsonBuilder::HandleSet(StatusWithSize written) {
1037 json_size_ = written.size();
1041 set_statuses(written.status());
1045constexpr void JsonBuilder::HandleAdd(StatusWithSize written,
1046 size_t starting_size,
1048 update_status(written.status());
1050 json_size_ += written.size();
1052 json_size_ = starting_size - 1;
1055 buffer_[json_size_++] = terminator;
1056 buffer_[json_size_] =
'\0';
Definition: builder.h:159
constexpr JsonArray & Append(const T &value)
Definition: builder.h:806
constexpr JsonArray & Extend(const Iterable &iterable)
Definition: builder.h:818
constexpr NestedJsonArray AppendNestedArray()
Appends a nested array to this array.
Definition: builder.h:809
constexpr NestedJsonObject AppendNestedObject()
Appends a nested object to this array.
Definition: builder.h:813
Definition: builder.h:501
Definition: builder.h:260
constexpr Status status() const
Definition: builder.h:310
constexpr bool IsArray() const
True if the top-level JSON entity is an array.
Definition: builder.h:282
constexpr JsonBuilder(char *buffer, size_t buffer_size)
Initializes to the value null. buffer_size must be at least 5.
Definition: builder.h:270
constexpr JsonObject & StartObject()
Definition: builder.h:359
constexpr size_t max_size() const
The maximum size of the JSON string, excluding the null terminator.
Definition: builder.h:297
constexpr bool IsValue() const
True if the top-level JSON entity is a simple value (not array or object).
Definition: builder.h:277
constexpr Status last_status() const
Definition: builder.h:314
constexpr JsonBuilder(span< char > buffer)
Initializes to the value null. buffer.size() must be at least 5.
Definition: builder.h:266
constexpr const char * data() const
Pointer to the serialized JSON, which is always a null-terminated string.
Definition: builder.h:291
constexpr Status SetValue(const T &value)
Clears the JSON and sets it to a single JSON value (see JsonValue::Set).
Definition: builder.h:843
constexpr size_t size() const
The current size of the JSON string, excluding the null terminator.
Definition: builder.h:294
constexpr bool ok() const
True if.
Definition: builder.h:300
constexpr void clear()
Sets the JSON null and clears the status.
Definition: builder.h:319
constexpr JsonArray & StartArray()
Definition: builder.h:344
constexpr void clear_status()
Resets status() and last_status().
Definition: builder.h:322
static constexpr size_t MinBufferSize()
JsonBuilder requires at least 5 characters in its buffer.
Definition: builder.h:263
constexpr JsonValue & StartValue()
Definition: builder.h:330
constexpr bool IsObject() const
True if the top-level JSON entity is an object.
Definition: builder.h:285
Definition: builder.h:212
constexpr JsonObject & Add(std::string_view key, const T &value)
Definition: builder.h:828
Definition: builder.h:116
constexpr Status Set(const T &value)
Definition: builder.h:802
constexpr NestedJsonObject AppendNestedObject()
Appends a new nested object to this nested array.
Definition: builder.h:781
constexpr NestedJsonArray AppendNestedArray()
Appends a new nested array to this nested array.
Definition: builder.h:777
constexpr NestedJsonArray & Append(const T &value)
Appends to the nested array.
Definition: builder.h:773
constexpr NestedJsonArray AddNestedArray(std::string_view key)
Adds a nested array to the nested object.
Definition: builder.h:785
constexpr NestedJsonObject & Add(std::string_view key, const T &value)
Adds a key-value pair to the nested object.
Definition: builder.h:796
constexpr NestedJsonObject AddNestedObject(std::string_view key)
Adds a nested object to the nested object.
Definition: builder.h:790
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
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:686
Definition: builder.h:688