///|
fn imports_ledger_json(s : ImportsLedger) -> Json {
let ledger : Map[String, Json] = Map([])
ledger.set(
"import_section_total_bytes",
int_json(s.import_section_total_bytes),
)
ledger.set("section_header_bytes", int_json(s.section_header_bytes))
ledger.set("count_prefix_bytes", int_json(s.count_prefix_bytes))
ledger.set("entry_bytes", int_json(s.entry_bytes))
ledger.set(
"module_name_encoding_bytes",
int_json(s.module_name_encoding_bytes),
)
ledger.set(
"module_length_prefix_bytes",
int_json(s.module_length_prefix_bytes),
)
ledger.set("module_utf8_bytes", int_json(s.module_utf8_bytes))
ledger.set("field_name_encoding_bytes", int_json(s.field_name_encoding_bytes))
ledger.set("field_length_prefix_bytes", int_json(s.field_length_prefix_bytes))
ledger.set("field_utf8_bytes", int_json(s.field_utf8_bytes))
ledger.set("descriptor_bytes", int_json(s.descriptor_bytes))
Json::object(ledger)
}
///|
fn imports_range_json(range : ImportByteRange) -> Json {
let row : Map[String, Json] = Map([])
row.set("offset", int_json(range.offset))
row.set("size", int_json(range.size))
Json::object(row)
}
///|
fn imports_optional_range_json(range : ImportByteRange?) -> Json {
match range {
Some(r) => imports_range_json(r)
None => Json::null()
}
}
///|
fn imports_uint_json(value : UInt) -> Json {
Json::number(value.to_double(), repr=value.to_string())
}
///|
fn imports_optional_uint_json(value : UInt?) -> Json {
match value {
Some(n) => imports_uint_json(n)
None => Json::null()
}
}
///|
fn imports_counts_json(counts : ImportKindCounts) -> Json {
let row : Map[String, Json] = Map([])
row.set("function", int_json(counts.functions))
row.set("table", int_json(counts.tables))
row.set("memory", int_json(counts.memories))
row.set("global", int_json(counts.globals))
row.set("tag", int_json(counts.tags))
Json::object(row)
}
///|
fn imports_limits_json(limits : ImportLimits?) -> Json {
match limits {
None => Json::null()
Some(limits) => {
let row : Map[String, Json] = Map([])
row.set("flags", int_json(limits.flags))
row.set("minimum", imports_uint_json(limits.minimum))
row.set("maximum", imports_optional_uint_json(limits.maximum))
Json::object(row)
}
}
}
///|
fn imports_json(report : ImportsReport) -> Json {
let root : Map[String, Json] = Map([])
root.set("format", Json::string("moonsize-imports"))
root.set("schema_version", int_json(1))
root.set("file_size", int_json(report.file_size))
root.set("sha256", Json::string(report.sha256))
root.set("supported_scope", Json::string(report.supported_scope))
root.set("section", imports_optional_range_json(report.section))
root.set("count_encoding", imports_optional_range_json(report.count_encoding))
root.set("entry_count", int_json(report.entry_count))
root.set("kind_counts", imports_counts_json(report.kind_counts))
root.set("ledger", imports_ledger_json(report.ledger))
root.set(
"modules",
Json::array(
report.modules.map(fn(group) {
let row : Map[String, Json] = Map([])
row.set("module", Json::string(group.module_name))
row.set("entry_count", int_json(group.entry_count))
row.set("kind_counts", imports_counts_json(group.kind_counts))
row.set("entry_bytes", int_json(group.entry_bytes))
row.set("ordinals", Json::array(group.ordinals.map(int_json)))
Json::object(row)
}),
),
)
root.set(
"entries",
Json::array(
report.entries.map(fn(entry) {
let row : Map[String, Json] = Map([])
row.set("ordinal", int_json(entry.ordinal))
row.set("kind", Json::string(entry.kind))
row.set("kind_index", int_json(entry.kind_index))
row.set("module", Json::string(entry.module_name))
row.set("field", Json::string(entry.field))
row.set("encoding", imports_range_json(entry.encoding))
row.set("module_encoding", imports_range_json(entry.module_encoding))
row.set("field_encoding", imports_range_json(entry.field_encoding))
row.set("descriptor", imports_range_json(entry.descriptor))
row.set(
"module_length_prefix_bytes",
int_json(entry.module_length_prefix_bytes),
)
row.set("module_utf8_bytes", int_json(entry.module_utf8_bytes))
row.set(
"field_length_prefix_bytes",
int_json(entry.field_length_prefix_bytes),
)
row.set("field_utf8_bytes", int_json(entry.field_utf8_bytes))
row.set("type_index", imports_optional_uint_json(entry.type_index))
row.set("limits", imports_limits_json(entry.limits))
row.set("value_type", path_optional_string(entry.value_type))
row.set("mutability", optional_index_json(entry.mutability))
Json::object(row)
}),
),
)
Json::object(root)
}
///|
pub fn render_imports_json(report : ImportsReport) -> String {
imports_json(report).stringify(indent=2) + "\n"
}
///|
fn imports_counts_text(c : ImportKindCounts) -> String {
"function \{c.functions}, table \{c.tables}, memory \{c.memories}, global \{c.globals}, tag \{c.tags}"
}
///|
fn imports_range_text(r : ImportByteRange) -> String {
"file offset \{r.offset}, \{r.size} B"
}
///|
pub fn render_imports(report : ImportsReport, top : Int) -> String {
let out = StringBuilder()
let s = report.ledger
out.write_string("HOST IMPORT DECLARATIONS\n\n")
out.write_string("Input: \{report.file_size} B; SHA-256 \{report.sha256}\n")
out.write_string(
"Declarations: \{report.entry_count}; " +
imports_counts_text(report.kind_counts) +
"\n",
)
out.write_string(
"Import section: " +
report.section.map(imports_range_text).unwrap_or("absent") +
"\n",
)
out.write_string(
"Import section bytes: \{s.import_section_total_bytes} B = section header \{s.section_header_bytes} B + count prefix \{s.count_prefix_bytes} B + declarations \{s.entry_bytes} B\n",
)
out.write_string(
"Declaration encoding bytes: \{s.entry_bytes} B = module names \{s.module_name_encoding_bytes} B + field names \{s.field_name_encoding_bytes} B + descriptors \{s.descriptor_bytes} B\n",
)
out.write_string(
"Module-name encodings: \{s.module_name_encoding_bytes} B = length prefixes \{s.module_length_prefix_bytes} B + UTF-8 \{s.module_utf8_bytes} B\n",
)
out.write_string(
"Field-name encodings: \{s.field_name_encoding_bytes} B = length prefixes \{s.field_length_prefix_bytes} B + UTF-8 \{s.field_utf8_bytes} B\n",
)
out.write_string(
"\nMODULE SUMMARY (all modules; section header and count not apportioned)\n",
)
for group in report.modules {
out.write_string(
Json::string(group.module_name).stringify() +
" \{group.entry_count} declarations \{group.entry_bytes} B; " +
imports_counts_text(group.kind_counts) +
"; ordinals " +
group.ordinals.map(fn(n) { n.to_string() }).join(", ") +
"\n",
)
}
let sorted = report.entries.copy()
sorted.sort_by(fn(a, b) {
let order = b.encoding.size.compare(a.encoding.size)
if order == 0 {
a.ordinal.compare(b.ordinal)
} else {
order
}
})
let shown = top.max(0).min(sorted.length())
out.write_string(
"\nIMPORT ENTRIES: showing \{shown} of \{report.entry_count} (encoding size descending)\n",
)
out.write_string(
"ORDINAL KIND KIND INDEX ENCODED B FILE OFFSET MODULE FIELD TYPE INDEX\n",
)
for i in 0..