File format 6 · Rust SDK 1.0 preview
Read, write and verify PLXI packs.
A PLXI pack is one file of JSON records, sealed by a SHA-256 digest. The Rust SDK, plxi-sdk, opens, verifies, writes, merges and compares packs.
// `write` returns the whole pack as bytes. No file is touched.
let bytes = write(&records, None)?;
// Opening verifies the pack by default (digest, header, record count).
let pack = Pack::from_bytes(bytes, OpenOptions::default())?;
assert_eq!(pack.record_count(), 3);
assert!(!pack.has_appendix());
// Records come back in the format's sort order (entities before
// relations), spelled the way the writer emits them.
let out: Vec<String> = pack
.records()
.map(|r| r.map(|rec| rec.json_line().to_string()))
.collect::<Result<_, _>>()?;
assert_eq!(
out,
[
concat!(
r#"{"k":"ent","v":1,"id":"e1","t":"Person","#,
r#""name":"Ada","salience":0.5,"stub":false}"#
),
r#"{"k":"ent","v":1,"id":"e2","t":"Person","stub":false}"#,
r#"{"k":"rel","v":1,"src":"e1","tgt":"e2","kind":"knows"}"#,
]
);
for line in &out {
println!("{line}");
}
println!("sha256 = {}", pack.sha256_hex());
// Keep a copy on disk, for checking with standard tools.
std::fs::write("sample.plxi", pack.to_bytes())?;
println!("wrote sample.plxi, {} bytes", pack.to_bytes().len());
{"k":"ent","v":1,"id":"e1","t":"Person","name":"Ada","salience":0.5,"stub":false}
{"k":"ent","v":1,"id":"e2","t":"Person","stub":false}
{"k":"rel","v":1,"src":"e1","tgt":"e2","kind":"knows"}
sha256 = 068f161e337da4b2b0c319a3539b9c62f4b15715d0f3c4de8e1664e5ef66bb28
wrote sample.plxi, 544 bytesRan with cargo run --example 01_write_and_read · exit status 0
// Change one letter in the record text after the pack was sealed:
// "Person" becomes "person". The JSON is still valid; the digest
// no longer matches.
let mut damaged = good;
let at = damaged
.windows(6)
.position(|w| w == b"Person")
.expect("the record text contains \"Person\"");
damaged[at] = b'p';
// The default open refuses it and names the reason.
let err = Pack::from_bytes(damaged.clone(), OpenOptions::default())
.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ChecksumMismatch);
assert_eq!(err.kind().as_str(), "checksum_mismatch");
println!("refused: {err}");
refused: checksum_mismatch: the file's SHA-256 digest does not match the one recorded in its footerRan with cargo run --example 02_verify · exit status 0
Example 1 writes a three-record pack and saves it. Example 2 changes one letter after sealing, and opening refuses the file. All eight examples
- 111 / 111 conformance cases passed by the Rust SDK, corpus version 1, recorded Results on plxi.org
- 257 bytes header line, fixed width
- SHA-256 digest in the footer, over every byte between header line and footer
- 19 record kinds, ranks 0 to 18
- 8 Rust examples, each shown with its recorded output
- Concepts
What a pack is, how its bytes are laid out, and what opening one checks.
- Guides
Open, read, write, merge and compare packs with the Rust SDK.
- Reference
Every public function and type of the Rust SDK.
- Specification
The format itself, section by section, on plxi.org.
- Conformance
The 111 test cases and what a conformance level claim requires, on plxi.org.
Not a developer? Help