JSONWriter in QEMU
struct JSONWriter {
bool pretty;
bool need_comma;
GString *contents;
// GByteArray 是 glibc 的一个 structure,表示一个 byte list
GByteArray *container_is_array;
};
首先要明白 JSON 的基本结构:
- Key 都是字符串
- Value 可以是字符串,数字,
{} object
或者[] object
。
maybe_comma_name()
QEMU
给你一个名字:
- 想要将其作为 key,或者
- 单纯就想给 array 里的上一个 entry 补一个逗号。
判断要怎么插入到当前的 JSON stream 中去:
- 要不要给上一个 key value pair / array entry 补上逗号?
- 如果在
{}
里,也就是想要作为 key,那么需要加引号与冒号。
static void maybe_comma_name(JSONWriter *writer, const char *name)
{
// need_comma 初始化的时候是 False
if (writer->need_comma) {
g_string_append_c(writer->contents, ',');
pretty_newline_or_space(writer);
} else {
// 如果我们的 writer 已经有内容了
// 就换行缩进格式化一下,一般来说不用格式化,所以我们可以忽略这个 block
if (writer->contents->len) {
pretty_newline(writer);
}
// 这次加了一个 key value pair,所以下一次要加逗号了。
writer->need_comma = true;
}
// 如果我们在 {} 里面而非 []
if (in_object(writer)) {
// 加上引号:name 变 "name"
quoted_str(writer, name);
// 加冒号表示这是一个 key
g_string_append(writer->contents, ": ");
}
}
in_object()
QEMU
当一下两个条件同时满足时返回 true:
- 第一个条件可以忽略,基本上是必然会满足的,
- 当前所在的这一层 object 是一个
{}
而不是[]
。
白话来说,就是表示现在是否在 {}
里面而非 []
。
static bool in_object(JSONWriter *writer)
{
unsigned depth = writer->container_is_array->len;
return depth && !writer->container_is_array->data[depth - 1];
}
enter_container()
/ leave_container()
QEMU
所谓 container 指的是 []
或者 {}
。
// is_array 表示我们要 enter 的是 [] 还是 {}
static void enter_container(JSONWriter *writer, bool is_array)
{
// container_is_array 是一个 GByteArray 类型的,包含两个 fields:data 和 len
// 分别表示起始地址和长度
// len 表示 depth
unsigned depth = writer->container_is_array->len;
// depth 加 1,因为我们进入了 container
g_byte_array_set_size(writer->container_is_array, depth + 1);
// 因为 GByteArray 是一个 byte list,每一个 byte 正好就是一个 bool,
// 所以每一个 entry 表示的就是这个 depth 的元素是一个 array 还是 object
writer->container_is_array->data[depth] = is_array;
// 因为我们是 enter container,所以不需要逗号。
writer->need_comma = false;
}
// 可以用上面的注释解释
static void leave_container(JSONWriter *writer, bool is_array)
{
unsigned depth = writer->container_is_array->len;
assert(depth);
// 保证 } 和 { 匹配,] 和 [ 匹配
assert(writer->container_is_array->data[depth - 1] == is_array);
g_byte_array_set_size(writer->container_is_array, depth - 1);
writer->need_comma = true;
}
json_writer_start_object()
/ json_writer_end_object()
QEMU
以 name 为 key,开启一个新的 {}
作为 value。
void json_writer_start_object(JSONWriter *writer, const char *name)
{
maybe_comma_name(writer, name);
g_string_append_c(writer->contents, '{');
enter_container(writer, false);
}
void json_writer_end_object(JSONWriter *writer)
{
leave_container(writer, false);
pretty_newline(writer);
g_string_append_c(writer->contents, '}');
}
json_writer_start_array()
/ json_writer_end_array()
QEMU
以 name 为 key,开启一个新的 []
作为 value。
void json_writer_start_array(JSONWriter *writer, const char *name)
{
maybe_comma_name(writer, name);
g_string_append_c(writer->contents, '[');
enter_container(writer, true);
}
void json_writer_end_array(JSONWriter *writer)
{
leave_container(writer, true);
pretty_newline(writer);
g_string_append_c(writer->contents, ']');
}
json_writer_get()
QEMU
很简单,就是把当前 content 的 string 内容拿出来。
json_writer_bool()
/ json_writer_null()
/ json_writer_int64()
/ json_writer_uint64()
/ json_writer_double()
/ json_writer_str()
QEMU
都大同小异,都是把传进来的 name 作为 key,然后 value 写不同类型的值,不作赘述。
🗞️ Recent Posts