/src/serenity/AK/JsonArraySerializer.h
Line | Count | Source |
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 | | |
17 | | namespace AK { |
18 | | |
19 | | template<typename Builder> |
20 | | inline constexpr bool IsLegacyBuilder = requires(Builder builder) { builder.try_append('\0'); }; |
21 | | |
22 | | template<typename Builder = void> |
23 | | class JsonObjectSerializer; |
24 | | |
25 | | template<typename Builder = void> |
26 | | class JsonArraySerializer { |
27 | | public: |
28 | | static ErrorOr<JsonArraySerializer> try_create(Builder& builder) |
29 | 0 | { |
30 | | if constexpr (IsLegacyBuilder<Builder>) |
31 | 0 | TRY(builder.try_append('[')); |
32 | | else |
33 | | TRY(builder.append('[')); |
34 | 0 | return JsonArraySerializer { builder }; |
35 | 0 | } |
36 | | |
37 | | JsonArraySerializer(JsonArraySerializer&& other) |
38 | 0 | : m_builder(other.m_builder) |
39 | 0 | , m_empty(other.m_empty) |
40 | 0 | , m_finished(exchange(other.m_finished, true)) |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | JsonArraySerializer(JsonArraySerializer const&) = delete; |
45 | | |
46 | | #ifndef KERNEL |
47 | | ErrorOr<void> add(JsonValue const& value) |
48 | 0 | { |
49 | 0 | TRY(begin_item()); |
50 | 0 | value.serialize(m_builder); |
51 | 0 | return {}; |
52 | 0 | } |
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(ByteString 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 | 0 | { |
183 | 0 | VERIFY(!m_finished); |
184 | 0 | m_finished = true; |
185 | | if constexpr (IsLegacyBuilder<Builder>) |
186 | 0 | TRY(m_builder.try_append(']')); |
187 | | else |
188 | | TRY(m_builder.append(']')); |
189 | 0 | return {}; |
190 | 0 | } |
191 | | |
192 | | private: |
193 | | explicit JsonArraySerializer(Builder& builder) |
194 | 0 | : m_builder(builder) |
195 | 0 | { |
196 | 0 | } |
197 | | |
198 | | ErrorOr<void> begin_item() |
199 | 0 | { |
200 | 0 | VERIFY(!m_finished); |
201 | 0 | if (!m_empty) { |
202 | | if constexpr (IsLegacyBuilder<Builder>) |
203 | 0 | TRY(m_builder.try_append(',')); |
204 | | else |
205 | | TRY(m_builder.append(',')); |
206 | 0 | } |
207 | 0 | m_empty = false; |
208 | 0 | return {}; |
209 | 0 | } |
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 |
217 | | template<> |
218 | | struct JsonArraySerializer<void> { |
219 | | template<typename Builder> |
220 | | static ErrorOr<JsonArraySerializer<Builder>> try_create(Builder& builder) |
221 | 0 | { |
222 | 0 | return JsonArraySerializer<Builder>::try_create(builder); |
223 | 0 | } |
224 | | }; |
225 | | |
226 | | } |
227 | | |
228 | | #if USING_AK_GLOBALLY |
229 | | using AK::JsonArraySerializer; |
230 | | #endif |