1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-07 21:17:07 +09:00

AK+Everywhere: Convert JSON value serialization to String

This removes the use of StringBuilder::OutputType (which was ByteString,
and only used by the JSON classes). And it removes the StringBuilder
template parameter from the serialization methods; this was only ever
used with StringBuilder, so a template is pretty overkill here.
This commit is contained in:
Timothy Flynn 2025-02-17 15:08:17 -05:00 committed by Tim Flynn
parent 2c03de60da
commit fe2dff4944
Notes: github-actions[bot] 2025-02-21 00:28:53 +00:00
15 changed files with 98 additions and 95 deletions

View file

@ -13,6 +13,7 @@ set(SOURCES
Format.cpp
GenericLexer.cpp
Hex.cpp
JsonArray.cpp
JsonObject.cpp
JsonParser.cpp
JsonValue.cpp

30
AK/JsonArray.cpp Normal file
View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/JsonArray.h>
#include <AK/JsonArraySerializer.h>
#include <AK/StringBuilder.h>
namespace AK {
String JsonArray::serialized() const
{
StringBuilder builder;
serialize(builder);
return MUST(builder.to_string());
}
void JsonArray::serialize(StringBuilder& builder) const
{
auto serializer = MUST(JsonArraySerializer<>::try_create(builder));
for_each([&](auto const& value) {
MUST(serializer.add(value));
});
MUST(serializer.finish());
}
}

View file

@ -8,8 +8,8 @@
#include <AK/Concepts.h>
#include <AK/Error.h>
#include <AK/JsonArraySerializer.h>
#include <AK/JsonValue.h>
#include <AK/String.h>
#include <AK/Vector.h>
namespace AK {
@ -72,11 +72,8 @@ public:
ErrorOr<void> append(JsonValue value) { return m_values.try_append(move(value)); }
void set(size_t index, JsonValue value) { m_values.at(index) = move(value); }
template<typename Builder>
typename Builder::OutputType serialized() const;
template<typename Builder>
void serialize(Builder&) const;
String serialized() const;
void serialize(StringBuilder&) const;
template<typename Callback>
void for_each(Callback callback)
@ -118,22 +115,6 @@ private:
Vector<JsonValue> m_values;
};
template<typename Builder>
inline void JsonArray::serialize(Builder& builder) const
{
auto serializer = MUST(JsonArraySerializer<>::try_create(builder));
for_each([&](auto& value) { MUST(serializer.add(value)); });
MUST(serializer.finish());
}
template<typename Builder>
inline typename Builder::OutputType JsonArray::serialized() const
{
Builder builder;
serialize(builder);
return builder.to_byte_string();
}
}
#if USING_AK_GLOBALLY

View file

@ -6,7 +6,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "JsonObject.h"
#include <AK/JsonObject.h>
#include <AK/JsonObjectSerializer.h>
#include <AK/StringBuilder.h>
namespace AK {
@ -275,4 +277,21 @@ bool JsonObject::remove(StringView key)
return m_members.remove(key);
}
String JsonObject::serialized() const
{
StringBuilder builder;
serialize(builder);
return MUST(builder.to_string());
}
void JsonObject::serialize(StringBuilder& builder) const
{
auto serializer = MUST(JsonObjectSerializer<>::try_create(builder));
for_each_member([&](auto& key, auto& value) {
MUST(serializer.add(key, value));
});
MUST(serializer.finish());
}
}

View file

@ -8,12 +8,10 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/Concepts.h>
#include <AK/Error.h>
#include <AK/HashMap.h>
#include <AK/JsonArray.h>
#include <AK/JsonObjectSerializer.h>
#include <AK/JsonValue.h>
#include <AK/String.h>
@ -107,59 +105,13 @@ public:
bool remove(StringView key);
template<typename Builder>
typename Builder::OutputType serialized() const;
template<typename Builder>
void serialize(Builder&) const;
String serialized() const;
void serialize(StringBuilder&) const;
private:
OrderedHashMap<String, JsonValue> m_members;
};
template<typename Builder>
inline void JsonObject::serialize(Builder& builder) const
{
auto serializer = MUST(JsonObjectSerializer<>::try_create(builder));
for_each_member([&](auto& key, auto& value) {
MUST(serializer.add(key, value));
});
MUST(serializer.finish());
}
template<typename Builder>
inline typename Builder::OutputType JsonObject::serialized() const
{
Builder builder;
serialize(builder);
return builder.to_byte_string();
}
template<typename Builder>
inline void JsonValue::serialize(Builder& builder) const
{
m_value.visit(
[&](Empty const&) { builder.append("null"sv); },
[&](bool const& value) { builder.append(value ? "true"sv : "false"sv); },
[&](Arithmetic auto const& value) { builder.appendff("{}", value); },
[&](String const& value) {
builder.append('\"');
builder.append_escaped_for_json(value.bytes());
builder.append('\"');
},
[&](auto const& array_or_object) {
array_or_object->serialize(builder);
});
}
template<typename Builder>
inline typename Builder::OutputType JsonValue::serialized() const
{
Builder builder;
serialize(builder);
return builder.to_byte_string();
}
}
#if USING_AK_GLOBALLY

View file

@ -9,6 +9,7 @@
#include <AK/JsonObject.h>
#include <AK/JsonParser.h>
#include <AK/JsonValue.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
namespace AK {
@ -192,4 +193,28 @@ ErrorOr<JsonValue> JsonValue::from_string(StringView input)
return JsonParser(input).parse();
}
String JsonValue::serialized() const
{
StringBuilder builder;
serialize(builder);
return MUST(builder.to_string());
}
void JsonValue::serialize(StringBuilder& builder) const
{
m_value.visit(
[&](Empty const&) { builder.append("null"sv); },
[&](bool const& value) { builder.append(value ? "true"sv : "false"sv); },
[&](Arithmetic auto const& value) { builder.appendff("{}", value); },
[&](String const& value) {
builder.append('\"');
builder.append_escaped_for_json(value.bytes());
builder.append('\"');
},
[&](auto const& array_or_object) {
array_or_object->serialize(builder);
});
}
}

View file

@ -11,7 +11,6 @@
#include <AK/NonnullOwnPtr.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
namespace AK {
@ -77,10 +76,8 @@ public:
JsonValue& operator=(JsonArray&&);
JsonValue& operator=(JsonObject&&);
template<typename Builder>
typename Builder::OutputType serialized() const;
template<typename Builder>
void serialize(Builder&) const;
String serialized() const;
void serialize(StringBuilder&) const;
Optional<int> get_int() const { return get_integer<int>(); }
Optional<i32> get_i32() const { return get_integer<i32>(); }
@ -224,7 +221,7 @@ template<>
struct Formatter<JsonValue> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, JsonValue const& value)
{
return Formatter<StringView>::format(builder, value.serialized<StringBuilder>());
return Formatter<StringView>::format(builder, value.serialized());
}
};

View file

@ -19,7 +19,6 @@ public:
static constexpr size_t inline_capacity = 256;
using Buffer = Detail::ByteBuffer<inline_capacity>;
using OutputType = ByteString;
static ErrorOr<StringBuilder> create(size_t initial_capacity = inline_capacity);

View file

@ -754,7 +754,7 @@ void ArgsParser::autocomplete(FILE* file, StringView program_name, ReadonlySpan<
object.set("invariant_offset"sv, has_invariant ? option_to_complete.length() : 0u);
object.set("display_trivia"sv, StringView { option.help_string, strlen(option.help_string) });
object.set("trailing_trivia"sv, option.argument_mode == OptionArgumentMode::Required ? " "sv : ""sv);
outln(file, "{}", object.serialized<StringBuilder>());
outln(file, "{}", object.serialized());
};
if (option_to_complete.starts_with("--"sv)) {

View file

@ -7,7 +7,6 @@
#include <AK/Debug.h>
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <AK/StringBuilder.h>
#include <LibCore/EventLoop.h>
#include <LibDevTools/Connection.h>
@ -34,7 +33,7 @@ Connection::~Connection() = default;
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#packets
void Connection::send_message(JsonValue const& message)
{
auto serialized = message.serialized<StringBuilder>();
auto serialized = message.serialized();
if constexpr (DEVTOOLS_DEBUG) {
if (message.is_object() && message.as_object().get("error"sv).has_value())
@ -43,7 +42,7 @@ void Connection::send_message(JsonValue const& message)
dbgln("\x1b[1;32m<<\x1b[0m {}", serialized);
}
if (m_socket->write_formatted("{}:{}", serialized.length(), serialized).is_error()) {
if (m_socket->write_formatted("{}:{}", serialized.byte_count(), serialized).is_error()) {
if (on_connection_closed)
on_connection_closed();
}

View file

@ -82,7 +82,7 @@ ErrorOr<void> encode(Encoder& encoder, ByteBuffer const& value)
template<>
ErrorOr<void> encode(Encoder& encoder, JsonValue const& value)
{
return encoder.encode(value.serialized<StringBuilder>());
return encoder.encode(value.serialized());
}
template<>

View file

@ -274,7 +274,7 @@ inline void TestRunner::print_test_results_as_json() const
root.set("files_total"sv, m_counts.files_total);
root.set("duration"sv, m_total_elapsed_time_in_ms / 1000.0);
}
outln("{}", root.serialized<StringBuilder>());
outln("{}", root.serialized());
}
}

View file

@ -298,7 +298,7 @@ ErrorOr<void, Client::WrappedError> Client::send_success_response(HTTP::HttpRequ
keep_alive = it->value.trim_whitespace().equals_ignoring_ascii_case("keep-alive"sv);
result = make_success_response(move(result));
auto content = result.serialized<StringBuilder>();
auto content = result.serialized();
StringBuilder builder;
builder.append("HTTP/1.1 200 OK\r\n"sv);
@ -309,7 +309,7 @@ ErrorOr<void, Client::WrappedError> Client::send_success_response(HTTP::HttpRequ
builder.append("Connection: keep-alive\r\n"sv);
builder.append("Cache-Control: no-cache\r\n"sv);
builder.append("Content-Type: application/json; charset=utf-8\r\n"sv);
builder.appendff("Content-Length: {}\r\n", content.length());
builder.appendff("Content-Length: {}\r\n", content.byte_count());
builder.append("\r\n"sv);
builder.append(content);
@ -338,13 +338,13 @@ ErrorOr<void, Client::WrappedError> Client::send_error_response(HTTP::HttpReques
JsonObject result;
result.set("value"sv, move(error_response));
auto content = result.serialized<StringBuilder>();
auto content = result.serialized();
StringBuilder builder;
builder.appendff("HTTP/1.1 {} {}\r\n", error.http_status, reason);
builder.append("Cache-Control: no-cache\r\n"sv);
builder.append("Content-Type: application/json; charset=utf-8\r\n"sv);
builder.appendff("Content-Length: {}\r\n", content.length());
builder.appendff("Content-Length: {}\r\n", content.byte_count());
builder.append("\r\n"sv);
builder.append(content);

View file

@ -160,13 +160,13 @@ TEST_CASE(json_duplicate_keys)
json.set("test"sv, "foo"sv);
json.set("test"sv, "bar"sv);
json.set("test"sv, "baz"sv);
EXPECT_EQ(json.serialized<StringBuilder>(), "{\"test\":\"baz\"}");
EXPECT_EQ(json.serialized(), "{\"test\":\"baz\"}");
}
TEST_CASE(json_u64_roundtrip)
{
auto big_value = 0xffffffffffffffffull;
auto json = JsonValue(big_value).serialized<StringBuilder>();
auto json = JsonValue(big_value).serialized();
auto value = JsonValue::from_string(json);
EXPECT_EQ_FORCE(value.is_error(), false);
EXPECT_EQ(value.value().as_integer<u64>(), big_value);
@ -531,7 +531,7 @@ TEST_CASE(json_array_serialized)
auto raw_json = R"(["Hello",2,3.14,4,"World"])"sv;
auto json_value = MUST(JsonValue::from_string(raw_json));
auto array = json_value.as_array();
auto const& serialized_json = array.serialized<StringBuilder>();
auto const& serialized_json = array.serialized();
EXPECT_EQ(serialized_json, raw_json);
}

View file

@ -532,7 +532,7 @@ static bool g_in_assert = false;
assert_fail_result.set("assert_fail"sv, true);
assert_fail_result.set("result"sv, "assert_fail"sv);
assert_fail_result.set("output"sv, StringView { assert_failed_message, strlen(assert_failed_message) });
outln(saved_stdout_fd, "RESULT {}{}", assert_fail_result.serialized<StringBuilder>(), '\0');
outln(saved_stdout_fd, "RESULT {}{}", assert_fail_result.serialized(), '\0');
// (Attempt to) Ensure that messages are written before quitting.
fflush(saved_stdout_fd);
fflush(stderr);
@ -733,7 +733,7 @@ int main(int argc, char** argv)
result_object.set("test"sv, path);
ScopeGuard output_guard = [&] {
outln(saved_stdout_fd, "RESULT {}{}", result_object.serialized<StringBuilder>(), '\0');
outln(saved_stdout_fd, "RESULT {}{}", result_object.serialized(), '\0');
fflush(saved_stdout_fd);
};