///|
pub struct ObjectPreview {
id : UInt64
kind : String
class_name : String
payload_bytes : Int
array_length : Int?
text : String
truncated : Bool
}
///|
pub fn Value::display(self : Value) -> String {
match self {
Reference(0UL) => "null"
Reference(id) => "@" + id.to_string(radix=16)
Boolean(value) => if value { "true" } else { "false" }
Character(value) =>
// A Java char can contain an isolated surrogate, so keep its numeric form.
"U+" + value.to_string(radix=16)
ByteValue(value) | ShortValue(value) | IntValue(value) => value.to_string()
LongValue(value) => value.to_string() + "L"
FloatValue(value) => value.to_string() + "f"
DoubleValue(value) => value.to_string()
}
}
///|
fn preview_prefix(text : String, maximum : Int) -> (String, Bool) {
let chars = text.to_array()
if chars.length() <= maximum {
return (text, false)
}
(String::from_array(chars[0:maximum]), true)
}
///|
/// A one-level display: referenced objects are IDs and never recursively opened.
pub fn Summary::preview(
self : Summary,
id : UInt64,
max_items? : Int = 8,
max_chars? : Int = 256,
) -> ObjectPreview raise ParseError {
if max_items < 0 ||
max_items > 100_000 ||
max_chars < 0 ||
max_chars > 100_000 {
raise Invalid(0, "invalid preview limits")
}
if self.definitions.contains(id) {
let name = self.class_name(id).unwrap_or("")
let (text, clipped) = preview_prefix(
"class " + display_class_name(name),
max_chars,
)
return {
id,
kind: "class",
class_name: name,
payload_bytes: 0,
array_length: None,
text,
truncated: clipped,
}
}
let object = self.require_object(id)
let class_name = if object.kind == PrimitiveArray {
value_type_name(object.primitive_kind) + "[]"
} else {
self.class_name(object.class_id).unwrap_or("")
}
let builder = StringBuilder()
let mut omitted = false
let length = match object.kind {
Instance => {
builder.write_string(display_class_name(class_name) + "{")
let fields = self.instance_fields(id)
let count = if fields.length() < max_items {
fields.length()
} else {
max_items
}
for i in 0.. 0 {
builder.write_string(", ")
}
builder.write_string(fields[i].name + "=" + fields[i].value.display())
}
omitted = count < fields.length()
if omitted {
builder.write_string(", ...")
}
builder.write_string("}")
None
}
ObjectArray | PrimitiveArray => {
builder.write_string(display_class_name(class_name) + "[")
let values = self.array_values(id, limit=max_items)
for i in 0.. 0 {
builder.write_string(", ")
}
builder.write_string(values[i].display())
}
omitted = values.length() < object.length
if omitted {
builder.write_string(", ...")
}
builder.write_string("]")
Some(object.length)
}
}
let (text, clipped) = preview_prefix(builder.to_string(), max_chars)
{
id,
kind: object.kind.label(),
class_name,
payload_bytes: object.payload_bytes,
array_length: length,
text,
truncated: omitted || clipped,
}
}
///|
pub fn ObjectPreview::to_json(self : ObjectPreview) -> Json {
Json::object({
"id": json_id(self.id),
"kind": Json::string(self.kind),
"class_name": Json::string(self.class_name),
"payload_bytes": json_int(self.payload_bytes),
"array_length": self.array_length.map(json_int).unwrap_or(Json::null()),
"text": Json::string(self.text),
"truncated": Json::boolean(self.truncated),
})
}
///|
/// Exports a bounded page as JSON Lines; each object is a separate JSON document.
/// Arrays use their own item limit rather than expanding arbitrary-size payloads.
pub fn Summary::objects_jsonl(
self : Summary,
class_id? : UInt64 = 0UL,
offset? : Int = 0,
limit? : Int = 100,
array_limit? : Int = 20,
) -> String raise ParseError {
if array_limit < 0 || array_limit > 100_000 {
raise Invalid(0, "invalid array export limit")
}
let builder = StringBuilder()
for id in self.object_ids(class_id~, offset~, limit~) {
builder.write_string(self.object_json(id, limit=array_limit).stringify())
builder.write_string("\n")
}
builder.to_string()
}
///|
pub fn Summary::previews_jsonl(
self : Summary,
class_id? : UInt64 = 0UL,
offset? : Int = 0,
limit? : Int = 100,
max_items? : Int = 8,
max_chars? : Int = 256,
) -> String raise ParseError {
if max_items < 0 ||
max_items > 100_000 ||
max_chars < 0 ||
max_chars > 100_000 {
raise Invalid(0, "invalid preview export limits")
}
let builder = StringBuilder()
for id in self.object_ids(class_id~, offset~, limit~) {
builder.write_string(
self.preview(id, max_items~, max_chars~).to_json().stringify(),
)
builder.write_string("\n")
}
builder.to_string()
}