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:
parent
2c03de60da
commit
fe2dff4944
Notes:
github-actions[bot]
2025-02-21 00:28:53 +00:00
Author: https://github.com/trflynn89
Commit: fe2dff4944
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3631
Reviewed-by: https://github.com/awesomekling ✅
15 changed files with 98 additions and 95 deletions
|
@ -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
30
AK/JsonArray.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue