primase_foundations/lib.rs
1//! Building blocks for reading game files: checked byte reading, the hashes game files key their names by, vertex
2//! layouts and attribute decoding, an ordered parallel map, sRGB and texture-sampling arithmetic, and (behind the
3//! `compress` feature) the compression codecs games store their data in.
4//!
5//! The readers and decoders work on borrowed bytes and return a value or an error rather than panicking on malformed
6//! input; the library modules do no file, environment or process access (the one exception, loading a native Oodle
7//! library the caller names, is in `compress::oodle`). Each module states its conventions (byte order, normalization,
8//! rounding) in its own documentation, because file formats differ on exactly those points.
9//!
10//! - [`bytes`]: bounds-checked [`View`](bytes::View) and [`Cursor`](bytes::Cursor) readers. The byte order is stated
11//! on every multi-byte read, and a refused read reports the absolute offset it was at.
12//! - [`hash`]: CRC-32, Adler-32 (from any start value), Jenkins one-at-a-time (case-folded and exact), MD5 with its
13//! block function exposed, and SDBM. Inputs are never normalized.
14//! - [`vertex`]: DXGI vertex element formats, layouts with explicit or appended offsets, stream decoding, packed
15//! positions and tangents, and triangle-strip and index-buffer helpers.
16//! - [`parallel`]: an ordered, panic-safe parallel map over independent items, with the thread count passed in.
17//! - `scan` (Unix and Windows): many stored entries of a few large files read in the files' own order, in large
18//! (on Windows unbuffered) reads on a stated number of threads, each entry handed to the caller on the thread that
19//! read it: the whole-archive pass. The one module that reads files, by the paths its caller names.
20//! - [`color`]: the sRGB transfer curve in `f64` and `f32` and its byte forms.
21//! - [`sampling`]: texture sampling as GPUs define it: address modes, point, bilinear and trilinear filtering,
22//! level of detail, 2D and 3D.
23//! - `compress` (feature `compress`): one `Decompressor` / `Compressor` interface over LZ4, deflate, zlib, zstd,
24//! LZMA, Brotli, LZO1X, LZO2A and Oodle, and a frame-by-frame LZX decoder. Every decode takes the exact expected
25//! output size and refuses anything else.
26//! - `sqlite` (feature `sqlite`): the tables of an SQLite 3 file image read whole, a table's columns and every row's
27//! typed values, refusing what it does not read (a write-ahead log, a `WITHOUT ROWID` table, a damaged b-tree).
28//!
29//! # Example
30//!
31//! Read a small made-up record, then see what a truncated copy of it reports:
32//!
33//! ```
34//! use primase_foundations::bytes::{Cursor, Endian, Field};
35//! use primase_foundations::hash::crc32;
36//!
37//! // "DATA", a little-endian count of 2-byte entries, then the entries
38//! let file = [b'D', b'A', b'T', b'A', 2, 0, 0, 0, 0x34, 0x12, 0x78, 0x56];
39//!
40//! let mut cursor = Cursor::new(&file);
41//! assert_eq!(cursor.take(4)?, b"DATA");
42//! let count = cursor.count(Endian::Little, 2)?; // refused unless that many entries fit
43//! let mut entries = Vec::new();
44//! for _ in 0..count {
45//! entries.push(cursor.u16(Endian::Little)?);
46//! }
47//! assert_eq!(entries, [0x1234, 0x5678]);
48//! assert_eq!(crc32(b"123456789"), 0xcbf4_3926);
49//!
50//! // cut short, the read is refused with the field and the offset
51//! let mut cut = Cursor::new(&file[..6]);
52//! cut.take(4)?;
53//! let refusal = cut.count(Endian::Little, 2).field("entry count").unwrap_err();
54//! assert_eq!(refusal.to_string(), "entry count at 0x4: 4 bytes run past the end of 6");
55//! # Ok::<(), Box<dyn std::error::Error>>(())
56//! ```
57#![deny(missing_docs)]
58#![deny(clippy::disallowed_methods, clippy::disallowed_types)]
59// A reader of stored bytes never panics, wraps or truncates silently: every index, sum and narrowing is checked and
60// reports an error. Unit tests build their fixtures by index and are exempt.
61#![cfg_attr(
62 not(test),
63 deny(
64 clippy::indexing_slicing,
65 clippy::arithmetic_side_effects,
66 clippy::cast_possible_truncation
67 )
68)]
69
70pub mod bytes;
71pub mod color;
72#[cfg(feature = "compress")]
73pub mod compress;
74pub mod hash;
75pub mod parallel;
76pub mod sampling;
77#[cfg(any(unix, windows))]
78pub mod scan;
79#[cfg(feature = "sqlite")]
80pub mod sqlite;
81pub mod vertex;
82
83/// This crate's source files as `(name, bytes)`, for a caller that keys a disk cache by the code that computed its
84/// values: hashing them retires cached entries when any of them changes. A test keeps the list equal to the `src`
85/// folder.
86pub const SOURCES: &[(&str, &[u8])] = &[
87 ("foundations/bytes.rs", include_bytes!("bytes.rs")),
88 ("foundations/color.rs", include_bytes!("color.rs")),
89 (
90 "foundations/compress/lzo1x.rs",
91 include_bytes!("compress/lzo1x.rs"),
92 ),
93 (
94 "foundations/compress/lzo2a.rs",
95 include_bytes!("compress/lzo2a.rs"),
96 ),
97 ("foundations/compress/lzx.rs", include_bytes!("compress/lzx.rs")),
98 ("foundations/compress/mod.rs", include_bytes!("compress/mod.rs")),
99 (
100 "foundations/compress/oodle.rs",
101 include_bytes!("compress/oodle.rs"),
102 ),
103 (
104 "foundations/compress/oodle_framing.rs",
105 include_bytes!("compress/oodle_framing.rs"),
106 ),
107 (
108 "foundations/compress/reference.rs",
109 include_bytes!("compress/reference.rs"),
110 ),
111 ("foundations/hash.rs", include_bytes!("hash.rs")),
112 ("foundations/lib.rs", include_bytes!("lib.rs")),
113 ("foundations/parallel.rs", include_bytes!("parallel.rs")),
114 ("foundations/sampling.rs", include_bytes!("sampling.rs")),
115 ("foundations/scan.rs", include_bytes!("scan.rs")),
116 ("foundations/sqlite.rs", include_bytes!("sqlite.rs")),
117 ("foundations/vertex.rs", include_bytes!("vertex.rs")),
118];
119
120// The real-data inputs this crate's unit tests read (tests/inputs/mod.rs).
121#[cfg(test)]
122#[path = "../tests/inputs/mod.rs"]
123mod inputs;
124
125/// Makes `cargo test` compile and run the README's example.
126#[cfg(doctest)]
127#[doc = include_str!("../README.md")]
128struct ReadmeDoctests;