mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
JSON: Templatize the JSON serialization code
This makes it possible to use something other than a StringBuilder for serialization (and to produce something other than a String.) :^)
This commit is contained in:
parent
43ec733b61
commit
f6998b1817
Notes:
sideshowbarker
2024-07-19 12:50:10 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f6998b1817a
11 changed files with 145 additions and 109 deletions
|
@ -3,22 +3,4 @@
|
|||
|
||||
namespace AK {
|
||||
|
||||
void JsonArray::serialize(StringBuilder& builder) const
|
||||
{
|
||||
builder.append('[');
|
||||
for (int i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i].serialize(builder);
|
||||
if (i != size() - 1)
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(']');
|
||||
}
|
||||
|
||||
String JsonArray::serialized() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
serialize(builder);
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,8 +44,13 @@ public:
|
|||
void append(const JsonValue& value) { m_values.append(value); }
|
||||
void append(JsonValue&& value) { m_values.append(move(value)); }
|
||||
|
||||
String serialized() const;
|
||||
void serialize(StringBuilder&) const;
|
||||
template<typename Builder>
|
||||
typename Builder::OutputType serialized() const;
|
||||
|
||||
template<typename Builder>
|
||||
void serialize(Builder&) const;
|
||||
|
||||
String to_string() const { return serialized<StringBuilder>(); }
|
||||
|
||||
template<typename Callback>
|
||||
void for_each(Callback callback) const
|
||||
|
@ -60,6 +65,26 @@ private:
|
|||
Vector<JsonValue> m_values;
|
||||
};
|
||||
|
||||
template<typename Builder>
|
||||
inline void JsonArray::serialize(Builder& builder) const
|
||||
{
|
||||
builder.append('[');
|
||||
for (int i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i].serialize(builder);
|
||||
if (i != size() - 1)
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(']');
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
inline typename Builder::OutputType JsonArray::serialized() const
|
||||
{
|
||||
Builder builder;
|
||||
serialize(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::JsonArray;
|
||||
|
|
|
@ -3,28 +3,4 @@
|
|||
|
||||
namespace AK {
|
||||
|
||||
void JsonObject::serialize(StringBuilder& builder) const
|
||||
{
|
||||
int index = 0;
|
||||
builder.append('{');
|
||||
for_each_member([&] (auto& key, auto& value) {
|
||||
builder.append('"');
|
||||
builder.append(key);
|
||||
builder.append('"');
|
||||
builder.append(':');
|
||||
value.serialize(builder);
|
||||
if (index != size() - 1)
|
||||
builder.append(',');
|
||||
++index;
|
||||
});
|
||||
builder.append('}');
|
||||
}
|
||||
|
||||
String JsonObject::serialized() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
serialize(builder);
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonValue.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class JsonObject {
|
||||
public:
|
||||
JsonObject() { }
|
||||
JsonObject() {}
|
||||
~JsonObject() {}
|
||||
|
||||
JsonObject(const JsonObject& other)
|
||||
|
@ -63,13 +64,90 @@ public:
|
|||
callback(it.key, it.value);
|
||||
}
|
||||
|
||||
String serialized() const;
|
||||
void serialize(StringBuilder&) const;
|
||||
template<typename Builder>
|
||||
typename Builder::OutputType serialized() const;
|
||||
|
||||
template<typename Builder>
|
||||
void serialize(Builder&) const;
|
||||
|
||||
String to_string() const { return serialized<StringBuilder>(); }
|
||||
|
||||
private:
|
||||
HashMap<String, JsonValue> m_members;
|
||||
};
|
||||
|
||||
template<typename Builder>
|
||||
inline void JsonObject::serialize(Builder& builder) const
|
||||
{
|
||||
int index = 0;
|
||||
builder.append('{');
|
||||
for_each_member([&](auto& key, auto& value) {
|
||||
builder.append('"');
|
||||
builder.append(key);
|
||||
builder.append('"');
|
||||
builder.append(':');
|
||||
value.serialize(builder);
|
||||
if (index != size() - 1)
|
||||
builder.append(',');
|
||||
++index;
|
||||
});
|
||||
builder.append('}');
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
inline typename Builder::OutputType JsonObject::serialized() const
|
||||
{
|
||||
Builder builder;
|
||||
serialize(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
void JsonValue::serialize(Builder& builder) const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::String:
|
||||
builder.appendf("\"%s\"", m_value.as_string->characters());
|
||||
break;
|
||||
case Type::Array:
|
||||
m_value.as_array->serialize(builder);
|
||||
break;
|
||||
case Type::Object:
|
||||
m_value.as_object->serialize(builder);
|
||||
break;
|
||||
case Type::Bool:
|
||||
builder.append(m_value.as_bool ? "true" : "false");
|
||||
break;
|
||||
#ifndef KERNEL
|
||||
case Type::Double:
|
||||
builder.appendf("%g", m_value.as_double);
|
||||
break;
|
||||
#endif
|
||||
case Type::Int:
|
||||
builder.appendf("%d", m_value.as_int);
|
||||
break;
|
||||
case Type::UnsignedInt:
|
||||
builder.appendf("%u", m_value.as_uint);
|
||||
break;
|
||||
case Type::Undefined:
|
||||
builder.append("undefined");
|
||||
break;
|
||||
case Type::Null:
|
||||
builder.append("null");
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Builder>
|
||||
typename Builder::OutputType JsonValue::serialized() const
|
||||
{
|
||||
Builder builder;
|
||||
serialize(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::JsonObject;
|
||||
|
|
|
@ -158,50 +158,6 @@ void JsonValue::clear()
|
|||
m_value.as_string = nullptr;
|
||||
}
|
||||
|
||||
void JsonValue::serialize(StringBuilder& builder) const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::String:
|
||||
builder.appendf("\"%s\"", m_value.as_string->characters());
|
||||
break;
|
||||
case Type::Array:
|
||||
m_value.as_array->serialize(builder);
|
||||
break;
|
||||
case Type::Object:
|
||||
m_value.as_object->serialize(builder);
|
||||
break;
|
||||
case Type::Bool:
|
||||
builder.append(m_value.as_bool ? "true" : "false");
|
||||
break;
|
||||
#ifndef KERNEL
|
||||
case Type::Double:
|
||||
builder.appendf("%g", m_value.as_double);
|
||||
break;
|
||||
#endif
|
||||
case Type::Int:
|
||||
builder.appendf("%d", m_value.as_int);
|
||||
break;
|
||||
case Type::UnsignedInt:
|
||||
builder.appendf("%u", m_value.as_uint);
|
||||
break;
|
||||
case Type::Undefined:
|
||||
builder.append("undefined");
|
||||
break;
|
||||
case Type::Null:
|
||||
builder.append("null");
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
String JsonValue::serialized() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
serialize(builder);
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
JsonValue JsonValue::from_string(const StringView& input)
|
||||
{
|
||||
return JsonParser(input).parse();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <AK/AKString.h>
|
||||
#include <AK/IPv4Address.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
|
@ -57,14 +58,16 @@ public:
|
|||
JsonValue& operator=(JsonArray&&) = delete;
|
||||
JsonValue& operator=(JsonObject&&) = delete;
|
||||
|
||||
String serialized() const;
|
||||
void serialize(StringBuilder&) const;
|
||||
template<typename Builder>
|
||||
typename Builder::OutputType serialized() const;
|
||||
template<typename Builder>
|
||||
void serialize(Builder&) const;
|
||||
|
||||
String to_string(const String& default_value = {}) const
|
||||
String to_string() const
|
||||
{
|
||||
if (is_string())
|
||||
return as_string();
|
||||
return default_value;
|
||||
return serialized<StringBuilder>();
|
||||
}
|
||||
|
||||
Optional<IPv4Address> to_ipv4_address() const
|
||||
|
@ -151,7 +154,10 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
Type type() const { return m_type; }
|
||||
Type type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
bool is_null() const { return m_type == Type::Null; }
|
||||
bool is_undefined() const { return m_type == Type::Undefined; }
|
||||
|
@ -160,9 +166,15 @@ public:
|
|||
bool is_int() const { return m_type == Type::Int; }
|
||||
bool is_uint() const { return m_type == Type::UnsignedInt; }
|
||||
#ifndef KERNEL
|
||||
bool is_double() const { return m_type == Type::Double; }
|
||||
bool is_double() const
|
||||
{
|
||||
return m_type == Type::Double;
|
||||
}
|
||||
#endif
|
||||
bool is_array() const { return m_type == Type::Array; }
|
||||
bool is_array() const
|
||||
{
|
||||
return m_type == Type::Array;
|
||||
}
|
||||
bool is_object() const { return m_type == Type::Object; }
|
||||
bool is_number() const
|
||||
{
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace AK {
|
|||
|
||||
class StringBuilder {
|
||||
public:
|
||||
using OutputType = String;
|
||||
|
||||
explicit StringBuilder(int initial_capacity = 16);
|
||||
~StringBuilder() {}
|
||||
|
||||
|
@ -17,6 +19,8 @@ public:
|
|||
void appendf(const char*, ...);
|
||||
void appendvf(const char*, va_list);
|
||||
|
||||
String build() { return to_string(); }
|
||||
|
||||
String to_string();
|
||||
ByteBuffer to_byte_buffer();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <AK/JsonObject.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/LogStream.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/CFile.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -70,7 +71,7 @@ int main(int argc, char** argv)
|
|||
auto class_name = widget_object.get("class").to_string();
|
||||
dbg() << " " << name << " = new " << class_name << "(main_widget);";
|
||||
|
||||
widget_object.for_each_member([&](auto& property_name, auto& property_value) {
|
||||
widget_object.for_each_member([&](auto& property_name, const JsonValue& property_value) {
|
||||
if (property_name == "class")
|
||||
return;
|
||||
|
||||
|
@ -79,7 +80,7 @@ int main(int argc, char** argv)
|
|||
if (property_value.is_null())
|
||||
value = "{}";
|
||||
else
|
||||
value = property_value.serialized();
|
||||
value = property_value.to_string();
|
||||
|
||||
dbg() << " " << name << "->set_" << property_name << "(" << value << ");";
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "VBWidgetRegistry.h"
|
||||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/CFile.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GMenu.h>
|
||||
|
@ -318,7 +319,7 @@ void VBForm::load_from_file(const String& path)
|
|||
(void)property_name;
|
||||
(void)property_value;
|
||||
VBProperty& property = vbwidget->property(property_name);
|
||||
dbgprintf("Set property %s.%s to '%s'\n", widget_class.characters(), property_name.characters(), property_value.serialized().characters());
|
||||
dbgprintf("Set property %s.%s to '%s'\n", widget_class.characters(), property_name.characters(), property_value.to_string().characters());
|
||||
property.set_value(property_value);
|
||||
});
|
||||
m_widgets.append(vbwidget);
|
||||
|
@ -349,7 +350,7 @@ void VBForm::write_to_file(const String& path)
|
|||
widget_array.append(widget_object);
|
||||
}
|
||||
form_object.set("widgets", widget_array);
|
||||
file.write(form_object.serialized());
|
||||
file.write(form_object.to_string());
|
||||
}
|
||||
|
||||
void VBForm::dump()
|
||||
|
|
|
@ -208,7 +208,7 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
|
|||
description_object.set("offset", description->offset());
|
||||
array.append(move(description_object));
|
||||
}
|
||||
return array.serialized().to_byte_buffer();
|
||||
return array.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
|
||||
|
@ -241,7 +241,7 @@ Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
|
|||
region_object.set("name", region.name());
|
||||
array.append(move(region_object));
|
||||
}
|
||||
return array.serialized().to_byte_buffer();
|
||||
return array.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pci(InodeIdentifier)
|
||||
|
@ -294,7 +294,7 @@ Optional<KBuffer> procfs$net_tcp(InodeIdentifier)
|
|||
obj.set("sequence_number", socket->sequence_number());
|
||||
json.append(obj);
|
||||
});
|
||||
return json.serialized().to_byte_buffer();
|
||||
return json.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_vmo(InodeIdentifier identifier)
|
||||
|
@ -449,7 +449,7 @@ Optional<KBuffer> procfs$df(InodeIdentifier)
|
|||
fs_object.set("mount_point", mount.absolute_path());
|
||||
json.append(fs_object);
|
||||
});
|
||||
return json.serialized().to_byte_buffer();
|
||||
return json.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$cpuinfo(InodeIdentifier)
|
||||
|
@ -541,7 +541,7 @@ Optional<KBuffer> procfs$memstat(InodeIdentifier)
|
|||
json.set("super_physical_available", MM.super_physical_pages());
|
||||
json.set("kmalloc_call_count", g_kmalloc_call_count);
|
||||
json.set("kfree_call_count", g_kfree_call_count);
|
||||
return json.serialized().to_byte_buffer();
|
||||
return json.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$all(InodeIdentifier)
|
||||
|
@ -577,7 +577,7 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
|
|||
build_process(*Scheduler::colonel());
|
||||
for (auto* process : processes)
|
||||
build_process(*process);
|
||||
return array.serialized().to_byte_buffer();
|
||||
return array.to_string().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$inodes(InodeIdentifier)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/CFile.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -65,6 +66,6 @@ void print(const JsonValue& value, int indent)
|
|||
printf("\033[32;1m");
|
||||
else if (value.is_null() || value.is_undefined())
|
||||
printf("\033[34;1m");
|
||||
printf("%s", value.serialized().characters());
|
||||
printf("%s", value.to_string().characters());
|
||||
printf("\033[0m");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue