1 // Copyright 2024 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 18 #include "pw_assert/assert.h" 19 #include "pw_status/status.h" 20 21 namespace pw { 22 23 class JsonBuilder; 24 class NestedJsonObject; 25 26 namespace json_impl { 27 28 // Tracks how deeply nested an array or object is and the types of the 29 // structures it is nested in. 30 class Nesting { 31 public: 32 enum Type : uint16_t { kArray = 0, kObject = 1 }; 33 Nesting()34 constexpr Nesting() : json_offset_(0), depth_(0), types_(0) {} 35 36 constexpr Nesting(const Nesting&) = default; 37 constexpr Nesting& operator=(const Nesting&) = default; 38 Nest(size_t start,Type type)39 constexpr Nesting Nest(size_t start, Type type) const { 40 PW_ASSERT(depth_ < 16); // Arrays or objects may be nested at most 17 times 41 return Nesting(start, depth_ + 1, (types_ << 1) | type); 42 } 43 44 // The start of this structure in the original buffer. offset()45 constexpr size_t offset() const { return json_offset_; } 46 47 // Number of layers this array or object is nested within. depth()48 constexpr size_t depth() const { return depth_; } 49 CheckNesting(char * json)50 constexpr void CheckNesting(char* json) const { 51 PW_ASSERT(json[depth_] == '\0'); // Enclosing JSON has changed. 52 for (uint16_t i = 0; i < depth_; ++i) { 53 PW_ASSERT(json[i] == close(i)); // Enclosing JSON has changed. 54 } 55 } 56 57 // Writes closing ] or } and the final \0. Terminate(char * buffer)58 constexpr void Terminate(char* buffer) const { 59 for (uint16_t i = 0; i < depth_; ++i) { 60 buffer[i] = close(i); 61 } 62 buffer[depth_] = '\0'; 63 } 64 65 private: Nesting(size_t offset,uint16_t depth,uint16_t types)66 constexpr Nesting(size_t offset, uint16_t depth, uint16_t types) 67 : json_offset_(offset), depth_(depth), types_(types) {} 68 close(uint16_t i)69 constexpr char close(uint16_t i) const { 70 return (types_ & (1 << i)) == 0 ? ']' : '}'; 71 } 72 73 size_t json_offset_; 74 uint16_t depth_; // Depth only counts nested structures; [] is 0, [{}] is 1 75 uint16_t types_; 76 }; 77 78 // Represents a nested array or object. 79 class NestedJson { 80 public: 81 constexpr NestedJson(const NestedJson&) = delete; 82 constexpr NestedJson& operator=(const NestedJson&) = delete; 83 NestedJson(NestedJson && other)84 constexpr NestedJson(NestedJson&& other) : builder_(), nesting_() { 85 *this = std::move(other); 86 } 87 88 constexpr NestedJson& operator=(NestedJson&& other) { 89 builder_ = other.builder_; 90 nesting_ = other.nesting_; 91 other.builder_ = nullptr; 92 return *this; 93 } 94 builder()95 constexpr JsonBuilder& builder() const { return *builder_; } nesting()96 constexpr const Nesting& nesting() const { return nesting_; } 97 98 private: 99 friend class pw::JsonBuilder; 100 NestedJson(JsonBuilder & builder,const Nesting & nesting)101 constexpr NestedJson(JsonBuilder& builder, const Nesting& nesting) 102 : builder_(&builder), nesting_(nesting) {} 103 104 JsonBuilder* builder_; 105 Nesting nesting_; 106 }; 107 108 } // namespace json_impl 109 } // namespace pw 110