Serenity Operating System
at master 267 lines 7.3 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/JsonArraySerializer.h> 12#include <AK/Try.h> 13 14#ifndef KERNEL 15# include <AK/JsonValue.h> 16#endif 17 18namespace AK { 19 20template<typename Builder> 21class JsonObjectSerializer { 22public: 23 static ErrorOr<JsonObjectSerializer> try_create(Builder& builder) 24 { 25 if constexpr (IsLegacyBuilder<Builder>) 26 TRY(builder.try_append('{')); 27 else 28 TRY(builder.append('{')); 29 return JsonObjectSerializer { builder }; 30 } 31 32 JsonObjectSerializer(JsonObjectSerializer&& other) 33 : m_builder(other.m_builder) 34 , m_empty(other.m_empty) 35 , m_finished(exchange(other.m_finished, true)) 36 { 37 } 38 39 JsonObjectSerializer(JsonObjectSerializer const&) = delete; 40 41#ifndef KERNEL 42 ErrorOr<void> add(StringView key, JsonValue const& value) 43 { 44 TRY(begin_item(key)); 45 value.serialize(m_builder); 46 return {}; 47 } 48#endif 49 50 ErrorOr<void> add(StringView key, StringView value) 51 { 52 TRY(begin_item(key)); 53 if constexpr (IsLegacyBuilder<Builder>) { 54 TRY(m_builder.try_append('"')); 55 TRY(m_builder.try_append_escaped_for_json(value)); 56 TRY(m_builder.try_append('"')); 57 } else { 58 TRY(m_builder.append('"')); 59 TRY(m_builder.append_escaped_for_json(value)); 60 TRY(m_builder.append('"')); 61 } 62 return {}; 63 } 64 65#ifndef KERNEL 66 ErrorOr<void> add(StringView key, DeprecatedString const& value) 67 { 68 TRY(begin_item(key)); 69 if constexpr (IsLegacyBuilder<Builder>) { 70 TRY(m_builder.try_append('"')); 71 TRY(m_builder.try_append_escaped_for_json(value)); 72 TRY(m_builder.try_append('"')); 73 } else { 74 TRY(m_builder.append('"')); 75 TRY(m_builder.append_escaped_for_json(value)); 76 TRY(m_builder.append('"')); 77 } 78 return {}; 79 } 80#endif 81 82 ErrorOr<void> add(StringView key, char const* value) 83 { 84 TRY(begin_item(key)); 85 if constexpr (IsLegacyBuilder<Builder>) { 86 TRY(m_builder.try_append('"')); 87 TRY(m_builder.try_append_escaped_for_json({ value, __builtin_strlen(value) })); 88 TRY(m_builder.try_append('"')); 89 } else { 90 TRY(m_builder.append('"')); 91 TRY(m_builder.append_escaped_for_json({ value, __builtin_strlen(value) })); 92 TRY(m_builder.append('"')); 93 } 94 return {}; 95 } 96 97 ErrorOr<void> add(StringView key, bool value) 98 { 99 TRY(begin_item(key)); 100 if constexpr (IsLegacyBuilder<Builder>) 101 TRY(m_builder.try_append(value ? "true"sv : "false"sv)); 102 else 103 TRY(m_builder.append(value ? "true"sv : "false"sv)); 104 return {}; 105 } 106 107 ErrorOr<void> add(StringView key, int value) 108 { 109 TRY(begin_item(key)); 110 if constexpr (IsLegacyBuilder<Builder>) 111 TRY(m_builder.try_appendff("{}", value)); 112 else 113 TRY(m_builder.appendff("{}", value)); 114 return {}; 115 } 116 117 ErrorOr<void> add(StringView key, unsigned value) 118 { 119 TRY(begin_item(key)); 120 if constexpr (IsLegacyBuilder<Builder>) 121 TRY(m_builder.try_appendff("{}", value)); 122 else 123 TRY(m_builder.appendff("{}", value)); 124 return {}; 125 } 126 127 ErrorOr<void> add(StringView key, long value) 128 { 129 TRY(begin_item(key)); 130 if constexpr (IsLegacyBuilder<Builder>) 131 TRY(m_builder.try_appendff("{}", value)); 132 else 133 TRY(m_builder.appendff("{}", value)); 134 return {}; 135 } 136 137 ErrorOr<void> add(StringView key, long unsigned value) 138 { 139 TRY(begin_item(key)); 140 if constexpr (IsLegacyBuilder<Builder>) 141 TRY(m_builder.try_appendff("{}", value)); 142 else 143 TRY(m_builder.appendff("{}", value)); 144 return {}; 145 } 146 147 ErrorOr<void> add(StringView key, long long value) 148 { 149 TRY(begin_item(key)); 150 if constexpr (IsLegacyBuilder<Builder>) 151 TRY(m_builder.try_appendff("{}", value)); 152 else 153 TRY(m_builder.appendff("{}", value)); 154 return {}; 155 } 156 157 ErrorOr<void> add(StringView key, long long unsigned value) 158 { 159 TRY(begin_item(key)); 160 if constexpr (IsLegacyBuilder<Builder>) 161 TRY(m_builder.try_appendff("{}", value)); 162 else 163 TRY(m_builder.appendff("{}", value)); 164 return {}; 165 } 166 167#ifndef KERNEL 168 ErrorOr<void> add(StringView key, float value) 169 { 170 TRY(begin_item(key)); 171 if constexpr (IsLegacyBuilder<Builder>) 172 TRY(m_builder.try_appendff("{}", value)); 173 else 174 TRY(m_builder.appendff("{}", value)); 175 return {}; 176 } 177 178 ErrorOr<void> add(StringView key, double value) 179 { 180 TRY(begin_item(key)); 181 if constexpr (IsLegacyBuilder<Builder>) 182 TRY(m_builder.try_appendff("{}", value)); 183 else 184 TRY(m_builder.appendff("{}", value)); 185 return {}; 186 } 187#endif 188 189 ErrorOr<JsonArraySerializer<Builder>> add_array(StringView key) 190 { 191 TRY(begin_item(key)); 192 return JsonArraySerializer<Builder>::try_create(m_builder); 193 } 194 195 ErrorOr<JsonObjectSerializer<Builder>> add_object(StringView key) 196 { 197 TRY(begin_item(key)); 198 return JsonObjectSerializer::try_create(m_builder); 199 } 200 201 ErrorOr<void> finish() 202 { 203 VERIFY(!m_finished); 204 m_finished = true; 205 if constexpr (IsLegacyBuilder<Builder>) 206 TRY(m_builder.try_append('}')); 207 else 208 TRY(m_builder.append('}')); 209 return {}; 210 } 211 212private: 213 explicit JsonObjectSerializer(Builder& builder) 214 : m_builder(builder) 215 { 216 } 217 218 ErrorOr<void> begin_item(StringView key) 219 { 220 VERIFY(!m_finished); 221 if (!m_empty) { 222 if constexpr (IsLegacyBuilder<Builder>) 223 TRY(m_builder.try_append(',')); 224 else 225 TRY(m_builder.append(',')); 226 } 227 m_empty = false; 228 229 if constexpr (IsLegacyBuilder<Builder>) { 230 TRY(m_builder.try_append('"')); 231 TRY(m_builder.try_append_escaped_for_json(key)); 232 TRY(m_builder.try_append("\":"sv)); 233 } else { 234 TRY(m_builder.append('"')); 235 TRY(m_builder.append_escaped_for_json(key)); 236 TRY(m_builder.append("\":"sv)); 237 } 238 return {}; 239 } 240 241 Builder& m_builder; 242 bool m_empty { true }; 243 bool m_finished { false }; 244}; 245 246// Template magic to allow for JsonObjectSerializer<>::try_create(...) - Blame CxByte 247template<> 248struct JsonObjectSerializer<void> { 249 template<typename Builder> 250 static ErrorOr<JsonObjectSerializer<Builder>> try_create(Builder& builder) 251 { 252 return JsonObjectSerializer<Builder>::try_create(builder); 253 } 254}; 255 256template<typename Builder> 257ErrorOr<JsonObjectSerializer<Builder>> JsonArraySerializer<Builder>::add_object() 258{ 259 TRY(begin_item()); 260 return JsonObjectSerializer<Builder>::try_create(m_builder); 261} 262 263} 264 265#if USING_AK_GLOBALLY 266using AK::JsonObjectSerializer; 267#endif