Serenity Operating System
at master 230 lines 6.0 kB view raw
1/* 2 * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> 3 * Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/Error.h> 11#include <AK/Try.h> 12 13#ifndef KERNEL 14# include <AK/JsonValue.h> 15#endif 16 17namespace AK { 18 19template<typename Builder> 20inline constexpr bool IsLegacyBuilder = requires(Builder builder) { builder.try_append('\0'); }; 21 22template<typename Builder = void> 23class JsonObjectSerializer; 24 25template<typename Builder = void> 26class JsonArraySerializer { 27public: 28 static ErrorOr<JsonArraySerializer> try_create(Builder& builder) 29 { 30 if constexpr (IsLegacyBuilder<Builder>) 31 TRY(builder.try_append('[')); 32 else 33 TRY(builder.append('[')); 34 return JsonArraySerializer { builder }; 35 } 36 37 JsonArraySerializer(JsonArraySerializer&& other) 38 : m_builder(other.m_builder) 39 , m_empty(other.m_empty) 40 , m_finished(exchange(other.m_finished, true)) 41 { 42 } 43 44 JsonArraySerializer(JsonArraySerializer const&) = delete; 45 46#ifndef KERNEL 47 ErrorOr<void> add(JsonValue const& value) 48 { 49 TRY(begin_item()); 50 value.serialize(m_builder); 51 return {}; 52 } 53#endif 54 55 ErrorOr<void> add(StringView value) 56 { 57 TRY(begin_item()); 58 if constexpr (IsLegacyBuilder<Builder>) { 59 TRY(m_builder.try_append('"')); 60 TRY(m_builder.try_append_escaped_for_json(value)); 61 TRY(m_builder.try_append('"')); 62 } else { 63 TRY(m_builder.append('"')); 64 TRY(m_builder.append_escaped_for_json(value)); 65 TRY(m_builder.append('"')); 66 } 67 return {}; 68 } 69 70#ifndef KERNEL 71 ErrorOr<void> add(DeprecatedString const& value) 72 { 73 TRY(begin_item()); 74 if constexpr (IsLegacyBuilder<Builder>) { 75 TRY(m_builder.try_append('"')); 76 TRY(m_builder.try_append_escaped_for_json(value)); 77 TRY(m_builder.try_append('"')); 78 } else { 79 TRY(m_builder.append('"')); 80 TRY(m_builder.append_escaped_for_json(value)); 81 TRY(m_builder.append('"')); 82 } 83 return {}; 84 } 85#endif 86 87 ErrorOr<void> add(char const* value) 88 { 89 TRY(begin_item()); 90 if constexpr (IsLegacyBuilder<Builder>) { 91 TRY(m_builder.try_append('"')); 92 TRY(m_builder.try_append_escaped_for_json(value)); 93 TRY(m_builder.try_append('"')); 94 } else { 95 TRY(m_builder.append('"')); 96 TRY(m_builder.append_escaped_for_json(value)); 97 TRY(m_builder.append('"')); 98 } 99 return {}; 100 } 101 102 ErrorOr<void> add(bool value) 103 { 104 TRY(begin_item()); 105 if constexpr (IsLegacyBuilder<Builder>) 106 TRY(m_builder.try_append(value ? "true"sv : "false"sv)); 107 else 108 TRY(m_builder.append(value ? "true"sv : "false"sv)); 109 return {}; 110 } 111 112 ErrorOr<void> add(int value) 113 { 114 TRY(begin_item()); 115 if constexpr (IsLegacyBuilder<Builder>) 116 TRY(m_builder.try_appendff("{}", value)); 117 else 118 TRY(m_builder.appendff("{}", value)); 119 return {}; 120 } 121 122 ErrorOr<void> add(unsigned value) 123 { 124 TRY(begin_item()); 125 if constexpr (IsLegacyBuilder<Builder>) 126 TRY(m_builder.try_appendff("{}", value)); 127 else 128 TRY(m_builder.appendff("{}", value)); 129 return {}; 130 } 131 132 ErrorOr<void> add(long value) 133 { 134 TRY(begin_item()); 135 if constexpr (IsLegacyBuilder<Builder>) 136 TRY(m_builder.try_appendff("{}", value)); 137 else 138 TRY(m_builder.appendff("{}", value)); 139 return {}; 140 } 141 142 ErrorOr<void> add(long unsigned value) 143 { 144 TRY(begin_item()); 145 if constexpr (IsLegacyBuilder<Builder>) 146 TRY(m_builder.try_appendff("{}", value)); 147 else 148 TRY(m_builder.appendff("{}", value)); 149 return {}; 150 } 151 152 ErrorOr<void> add(long long value) 153 { 154 TRY(begin_item()); 155 if constexpr (IsLegacyBuilder<Builder>) 156 TRY(m_builder.try_appendff("{}", value)); 157 else 158 TRY(m_builder.appendff("{}", value)); 159 return {}; 160 } 161 162 ErrorOr<void> add(long long unsigned value) 163 { 164 TRY(begin_item()); 165 if constexpr (IsLegacyBuilder<Builder>) 166 TRY(m_builder.try_appendff("{}", value)); 167 else 168 TRY(m_builder.appendff("{}", value)); 169 return {}; 170 } 171 172 ErrorOr<JsonArraySerializer<Builder>> add_array() 173 { 174 TRY(begin_item()); 175 return JsonArraySerializer::try_create(m_builder); 176 } 177 178 // Implemented in JsonObjectSerializer.h 179 ErrorOr<JsonObjectSerializer<Builder>> add_object(); 180 181 ErrorOr<void> finish() 182 { 183 VERIFY(!m_finished); 184 m_finished = true; 185 if constexpr (IsLegacyBuilder<Builder>) 186 TRY(m_builder.try_append(']')); 187 else 188 TRY(m_builder.append(']')); 189 return {}; 190 } 191 192private: 193 explicit JsonArraySerializer(Builder& builder) 194 : m_builder(builder) 195 { 196 } 197 198 ErrorOr<void> begin_item() 199 { 200 VERIFY(!m_finished); 201 if (!m_empty) { 202 if constexpr (IsLegacyBuilder<Builder>) 203 TRY(m_builder.try_append(',')); 204 else 205 TRY(m_builder.append(',')); 206 } 207 m_empty = false; 208 return {}; 209 } 210 211 Builder& m_builder; 212 bool m_empty { true }; 213 bool m_finished { false }; 214}; 215 216// Template magic to allow for JsonArraySerializer<>::try_create(...) - Blame CxByte 217template<> 218struct JsonArraySerializer<void> { 219 template<typename Builder> 220 static ErrorOr<JsonArraySerializer<Builder>> try_create(Builder& builder) 221 { 222 return JsonArraySerializer<Builder>::try_create(builder); 223 } 224}; 225 226} 227 228#if USING_AK_GLOBALLY 229using AK::JsonArraySerializer; 230#endif