Example 8: Files, limits, errors
- file format 6
- Rust SDK 1.0 preview
Needs the Rust SDK
Write and open a file, open gzip input, cap the input size, and branch on error kinds.
This program also needs flate2 = "1.1" under [dependencies] in its Cargo.toml.
08_files_limits_errors.rsrust
// Files, gzip, a size limit, and handling errors by kind.
use std::io::Write as _;
use flate2::{write::GzEncoder, Compression};
use plxi_sdk::{write, write_to_path, ErrorKind, OpenOptions, Pack, Record};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let records = vec![
Record::from_json_line(r#"{"k":"ent","id":"e1","t":"Person"}"#)?,
Record::from_json_line(r#"{"k":"ent","id":"e2","t":"Person"}"#)?,
];
let id = std::process::id();
let dir = std::env::temp_dir().join(format!("plxi-example-{id}"));
std::fs::create_dir_all(&dir)?;
// Write to a file and open it by path.
let path = dir.join("people.plxi");
write_to_path(&path, &records, None)?;
let pack = Pack::open(&path, OpenOptions::default())?;
assert_eq!(pack.record_count(), 2);
// A gzip-compressed pack opens the same way: input that starts
// with the gzip magic bytes is inflated first.
let plain = write(&records, None)?;
let mut enc = GzEncoder::new(Vec::new(), Compression::default());
enc.write_all(&plain)?;
let gz = enc.finish()?;
let from_gz = Pack::from_bytes(gz.clone(), OpenOptions::default())?;
assert_eq!(from_gz.to_bytes(), plain.as_slice());
// No size limit applies unless one is set. With a limit, both the
// input and the inflated output are capped.
let cap = plain.len() as u64 - 1;
let capped = OpenOptions::default().with_max_input_bytes(cap);
let err = Pack::from_bytes(gz, capped).unwrap_err();
assert_eq!(err.kind(), ErrorKind::LimitExceeded);
assert_eq!(err.details()["max_input_bytes"], cap);
// Errors carry a stable kind, a message for people, and JSON
// details.
let missing = dir.join("nope.plxi");
let missing = Pack::open(missing, OpenOptions::default()).unwrap_err();
let what = match missing.kind() {
ErrorKind::Io => "could not read the file",
ErrorKind::ChecksumMismatch => "the file is damaged",
_ => "something else",
};
assert_eq!(what, "could not read the file");
let not_object = Record::from_json_line("[1,2]").unwrap_err();
assert_eq!(not_object.kind(), ErrorKind::InvalidRecord);
let cut_short = r#"{"k":"ent","id":"e1""#;
let cut_short = Record::from_json_line(cut_short).unwrap_err();
assert_eq!(cut_short.kind(), ErrorKind::Json);
let key = ErrorKind::from_key("limit_exceeded");
assert_eq!(key, Some(ErrorKind::LimitExceeded));
println!("{}", err.to_json());
std::fs::remove_dir_all(&dir)?;
Ok(())
}
Output
{"kind":"limit_exceeded","message":"the inflated input is larger than the caller's limit of 460 bytes; inflating stopped after 461 bytes","details":{"inflated_at_least":461,"max_input_bytes":460}}Ran with cargo run --example 08_files_limits_errors · exit status 0
Explained in: Errors and limits