/* * Copyright (c) 2019-2020, Sergey Bugaev * Copyright (c) 2022, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #ifndef KERNEL # include #endif namespace AK { template inline constexpr bool IsLegacyBuilder = requires(Builder builder) { builder.try_append('\0'); }; template class JsonObjectSerializer; template class JsonArraySerializer { public: static ErrorOr try_create(Builder& builder) { if constexpr (IsLegacyBuilder) TRY(builder.try_append('[')); else TRY(builder.append('[')); return JsonArraySerializer { builder }; } JsonArraySerializer(JsonArraySerializer&& other) : m_builder(other.m_builder) , m_empty(other.m_empty) , m_finished(exchange(other.m_finished, true)) { } JsonArraySerializer(const JsonArraySerializer&) = delete; ~JsonArraySerializer() { VERIFY(m_finished); } #ifndef KERNEL ErrorOr add(const JsonValue& value) { TRY(begin_item()); value.serialize(m_builder); return {}; } #endif ErrorOr add(StringView value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) { TRY(m_builder.try_append('"')); TRY(m_builder.try_append_escaped_for_json(value)); TRY(m_builder.try_append('"')); } else { TRY(m_builder.append('"')); TRY(m_builder.append_escaped_for_json(value)); TRY(m_builder.append('"')); } return {}; } #ifndef KERNEL ErrorOr add(const String& value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) { TRY(m_builder.try_append('"')); TRY(m_builder.try_append_escaped_for_json(value)); TRY(m_builder.try_append('"')); } else { TRY(m_builder.append('"')); TRY(m_builder.append_escaped_for_json(value)); TRY(m_builder.append('"')); } return {}; } #endif ErrorOr add(const char* value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) { TRY(m_builder.try_append('"')); TRY(m_builder.try_append_escaped_for_json(value)); TRY(m_builder.try_append('"')); } else { TRY(m_builder.append('"')); TRY(m_builder.append_escaped_for_json(value)); TRY(m_builder.append('"')); } return {}; } ErrorOr add(bool value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_append(value ? "true"sv : "false"sv)); else TRY(m_builder.append(value ? "true"sv : "false"sv)); return {}; } ErrorOr add(int value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr add(unsigned value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr add(long value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr add(long unsigned value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr add(long long value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr add(long long unsigned value) { TRY(begin_item()); if constexpr (IsLegacyBuilder) TRY(m_builder.try_appendff("{}", value)); else TRY(m_builder.appendff("{}", value)); return {}; } ErrorOr> add_array() { TRY(begin_item()); return JsonArraySerializer::try_create(m_builder); } // Implemented in JsonObjectSerializer.h ErrorOr> add_object(); ErrorOr finish() { VERIFY(!m_finished); m_finished = true; if constexpr (IsLegacyBuilder) TRY(m_builder.try_append(']')); else TRY(m_builder.append(']')); return {}; } private: explicit JsonArraySerializer(Builder& builder) : m_builder(builder) { } ErrorOr begin_item() { VERIFY(!m_finished); if (!m_empty) { if constexpr (IsLegacyBuilder) TRY(m_builder.try_append(',')); else TRY(m_builder.append(',')); } m_empty = false; return {}; } Builder& m_builder; bool m_empty { true }; bool m_finished { false }; }; // Template magic to allow for JsonArraySerializer<>::try_create(...) - Blame CxByte template<> struct JsonArraySerializer { template static ErrorOr> try_create(Builder& builder) { return JsonArraySerializer::try_create(builder); } }; } using AK::JsonArraySerializer;