Coverage Report

Created: 2025-12-18 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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