///|
/// Portable versioned snapshot containing the original text and namespace ID.
/// This preserves unknown fields and distinguishes it from a display-only report.
pub fn Snapshot::encode(self : Snapshot) -> String {
let document : Json = {
"format": "moonmount.snapshot",
"schema": 1,
"namespace_id": Json(self.token),
"mountinfo": Json(self.source_text),
}
document.stringify()
}
///|
/// Decode a saved snapshot and rebuild the validated immutable topology.
/// Namespace identity is retained; comparing different IDs raises NamespaceMismatch.
pub fn decode_snapshot(text : String) -> Snapshot raise MountError {
// JSON may expand a source character to six ASCII escape characters.
if text.length() > 64 * 1024 * 1024 {
raise InvalidSnapshot(reason="snapshot exceeds 64 Mi code-unit budget")
}
let document = @json.parse(text) catch {
_ => raise InvalidSnapshot(reason="invalid snapshot JSON")
}
match document {
{
"format": String("moonmount.snapshot"),
"schema": Number(1.0, ..),
"namespace_id": String(token),
"mountinfo": String(source),
..
} => parse(source, namespace_id=token)
_ =>
raise InvalidSnapshot(
reason="expected moonmount.snapshot schema 1 with namespace_id and mountinfo strings",
)
}
}