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