mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +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 {
|
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(const JsonValue& value) { m_values.append(value); }
|
||||||
void append(JsonValue&& value) { m_values.append(move(value)); }
|
void append(JsonValue&& value) { m_values.append(move(value)); }
|
||||||
|
|
||||||
String serialized() const;
|
template<typename Builder>
|
||||||
void serialize(StringBuilder&) const;
|
typename Builder::OutputType serialized() const;
|
||||||
|
|
||||||
|
template<typename Builder>
|
||||||
|
void serialize(Builder&) const;
|
||||||
|
|
||||||
|
String to_string() const { return serialized<StringBuilder>(); }
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each(Callback callback) const
|
void for_each(Callback callback) const
|
||||||
|
@ -60,6 +65,26 @@ private:
|
||||||
Vector<JsonValue> m_values;
|
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;
|
using AK::JsonArray;
|
||||||
|
|
|
@ -3,28 +3,4 @@
|
||||||
|
|
||||||
namespace AK {
|
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/AKString.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonValue.h>
|
#include <AK/JsonValue.h>
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
class JsonObject {
|
class JsonObject {
|
||||||
public:
|
public:
|
||||||
JsonObject() { }
|
JsonObject() {}
|
||||||
~JsonObject() {}
|
~JsonObject() {}
|
||||||
|
|
||||||
JsonObject(const JsonObject& other)
|
JsonObject(const JsonObject& other)
|
||||||
|
@ -63,13 +64,90 @@ public:
|
||||||
callback(it.key, it.value);
|
callback(it.key, it.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
String serialized() const;
|
template<typename Builder>
|
||||||
void serialize(StringBuilder&) const;
|
typename Builder::OutputType serialized() const;
|
||||||
|
|
||||||
|
template<typename Builder>
|
||||||
|
void serialize(Builder&) const;
|
||||||
|
|
||||||
|
String to_string() const { return serialized<StringBuilder>(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HashMap<String, JsonValue> m_members;
|
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;
|
using AK::JsonObject;
|
||||||
|
|
|
@ -158,50 +158,6 @@ void JsonValue::clear()
|
||||||
m_value.as_string = nullptr;
|
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)
|
JsonValue JsonValue::from_string(const StringView& input)
|
||||||
{
|
{
|
||||||
return JsonParser(input).parse();
|
return JsonParser(input).parse();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
#include <AK/IPv4Address.h>
|
#include <AK/IPv4Address.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
|
@ -57,14 +58,16 @@ public:
|
||||||
JsonValue& operator=(JsonArray&&) = delete;
|
JsonValue& operator=(JsonArray&&) = delete;
|
||||||
JsonValue& operator=(JsonObject&&) = delete;
|
JsonValue& operator=(JsonObject&&) = delete;
|
||||||
|
|
||||||
String serialized() const;
|
template<typename Builder>
|
||||||
void serialize(StringBuilder&) const;
|
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())
|
if (is_string())
|
||||||
return as_string();
|
return as_string();
|
||||||
return default_value;
|
return serialized<StringBuilder>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<IPv4Address> to_ipv4_address() const
|
Optional<IPv4Address> to_ipv4_address() const
|
||||||
|
@ -151,7 +154,10 @@ public:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_null() const { return m_type == Type::Null; }
|
bool is_null() const { return m_type == Type::Null; }
|
||||||
bool is_undefined() const { return m_type == Type::Undefined; }
|
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_int() const { return m_type == Type::Int; }
|
||||||
bool is_uint() const { return m_type == Type::UnsignedInt; }
|
bool is_uint() const { return m_type == Type::UnsignedInt; }
|
||||||
#ifndef KERNEL
|
#ifndef KERNEL
|
||||||
bool is_double() const { return m_type == Type::Double; }
|
bool is_double() const
|
||||||
|
{
|
||||||
|
return m_type == Type::Double;
|
||||||
|
}
|
||||||
#endif
|
#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_object() const { return m_type == Type::Object; }
|
||||||
bool is_number() const
|
bool is_number() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,8 @@ namespace AK {
|
||||||
|
|
||||||
class StringBuilder {
|
class StringBuilder {
|
||||||
public:
|
public:
|
||||||
|
using OutputType = String;
|
||||||
|
|
||||||
explicit StringBuilder(int initial_capacity = 16);
|
explicit StringBuilder(int initial_capacity = 16);
|
||||||
~StringBuilder() {}
|
~StringBuilder() {}
|
||||||
|
|
||||||
|
@ -17,6 +19,8 @@ public:
|
||||||
void appendf(const char*, ...);
|
void appendf(const char*, ...);
|
||||||
void appendvf(const char*, va_list);
|
void appendvf(const char*, va_list);
|
||||||
|
|
||||||
|
String build() { return to_string(); }
|
||||||
|
|
||||||
String to_string();
|
String to_string();
|
||||||
ByteBuffer to_byte_buffer();
|
ByteBuffer to_byte_buffer();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/JsonValue.h>
|
#include <AK/JsonValue.h>
|
||||||
#include <AK/LogStream.h>
|
#include <AK/LogStream.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibCore/CFile.h>
|
#include <LibCore/CFile.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ int main(int argc, char** argv)
|
||||||
auto class_name = widget_object.get("class").to_string();
|
auto class_name = widget_object.get("class").to_string();
|
||||||
dbg() << " " << name << " = new " << class_name << "(main_widget);";
|
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")
|
if (property_name == "class")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ int main(int argc, char** argv)
|
||||||
if (property_value.is_null())
|
if (property_value.is_null())
|
||||||
value = "{}";
|
value = "{}";
|
||||||
else
|
else
|
||||||
value = property_value.serialized();
|
value = property_value.to_string();
|
||||||
|
|
||||||
dbg() << " " << name << "->set_" << property_name << "(" << value << ");";
|
dbg() << " " << name << "->set_" << property_name << "(" << value << ");";
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "VBWidgetRegistry.h"
|
#include "VBWidgetRegistry.h"
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibCore/CFile.h>
|
#include <LibCore/CFile.h>
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
#include <LibGUI/GMenu.h>
|
#include <LibGUI/GMenu.h>
|
||||||
|
@ -318,7 +319,7 @@ void VBForm::load_from_file(const String& path)
|
||||||
(void)property_name;
|
(void)property_name;
|
||||||
(void)property_value;
|
(void)property_value;
|
||||||
VBProperty& property = vbwidget->property(property_name);
|
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);
|
property.set_value(property_value);
|
||||||
});
|
});
|
||||||
m_widgets.append(vbwidget);
|
m_widgets.append(vbwidget);
|
||||||
|
@ -349,7 +350,7 @@ void VBForm::write_to_file(const String& path)
|
||||||
widget_array.append(widget_object);
|
widget_array.append(widget_object);
|
||||||
}
|
}
|
||||||
form_object.set("widgets", widget_array);
|
form_object.set("widgets", widget_array);
|
||||||
file.write(form_object.serialized());
|
file.write(form_object.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VBForm::dump()
|
void VBForm::dump()
|
||||||
|
|
|
@ -208,7 +208,7 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
|
||||||
description_object.set("offset", description->offset());
|
description_object.set("offset", description->offset());
|
||||||
array.append(move(description_object));
|
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)
|
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());
|
region_object.set("name", region.name());
|
||||||
array.append(move(region_object));
|
array.append(move(region_object));
|
||||||
}
|
}
|
||||||
return array.serialized().to_byte_buffer();
|
return array.to_string().to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<KBuffer> procfs$pci(InodeIdentifier)
|
Optional<KBuffer> procfs$pci(InodeIdentifier)
|
||||||
|
@ -294,7 +294,7 @@ Optional<KBuffer> procfs$net_tcp(InodeIdentifier)
|
||||||
obj.set("sequence_number", socket->sequence_number());
|
obj.set("sequence_number", socket->sequence_number());
|
||||||
json.append(obj);
|
json.append(obj);
|
||||||
});
|
});
|
||||||
return json.serialized().to_byte_buffer();
|
return json.to_string().to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<KBuffer> procfs$pid_vmo(InodeIdentifier identifier)
|
Optional<KBuffer> procfs$pid_vmo(InodeIdentifier identifier)
|
||||||
|
@ -449,7 +449,7 @@ Optional<KBuffer> procfs$df(InodeIdentifier)
|
||||||
fs_object.set("mount_point", mount.absolute_path());
|
fs_object.set("mount_point", mount.absolute_path());
|
||||||
json.append(fs_object);
|
json.append(fs_object);
|
||||||
});
|
});
|
||||||
return json.serialized().to_byte_buffer();
|
return json.to_string().to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<KBuffer> procfs$cpuinfo(InodeIdentifier)
|
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("super_physical_available", MM.super_physical_pages());
|
||||||
json.set("kmalloc_call_count", g_kmalloc_call_count);
|
json.set("kmalloc_call_count", g_kmalloc_call_count);
|
||||||
json.set("kfree_call_count", g_kfree_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)
|
Optional<KBuffer> procfs$all(InodeIdentifier)
|
||||||
|
@ -577,7 +577,7 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
|
||||||
build_process(*Scheduler::colonel());
|
build_process(*Scheduler::colonel());
|
||||||
for (auto* process : processes)
|
for (auto* process : processes)
|
||||||
build_process(*process);
|
build_process(*process);
|
||||||
return array.serialized().to_byte_buffer();
|
return array.to_string().to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<KBuffer> procfs$inodes(InodeIdentifier)
|
Optional<KBuffer> procfs$inodes(InodeIdentifier)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/JsonValue.h>
|
#include <AK/JsonValue.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibCore/CFile.h>
|
#include <LibCore/CFile.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -65,6 +66,6 @@ void print(const JsonValue& value, int indent)
|
||||||
printf("\033[32;1m");
|
printf("\033[32;1m");
|
||||||
else if (value.is_null() || value.is_undefined())
|
else if (value.is_null() || value.is_undefined())
|
||||||
printf("\033[34;1m");
|
printf("\033[34;1m");
|
||||||
printf("%s", value.serialized().characters());
|
printf("%s", value.to_string().characters());
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue