# Contributing
## Build and test
You need a Rust toolchain of at least 1.99 (`rust-toolchain.toml` pins 1.99.0 and installs rustfmt and clippy).
```sh
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps
```
All four must pass; CI runs the first three on Linux and Windows. The tests that read your own game files skip unless `GAME_DATA` is set; the README's "Tests" section explains how, and [tests/inputs/README.md](tests/inputs/README.md) lists what they read. Never commit a game file, a decrypted or extracted piece of one, or a path from your machine: fixtures must be synthetic or generated by an independent program, and say how in the test that uses them.
## Conventions
- Library code never panics on bytes it is given: a read that cannot succeed is an error that says what was expected and where. `lib.rs` denies `clippy::indexing_slicing`, `clippy::arithmetic_side_effects` and `clippy::cast_possible_truncation` outside unit tests, so index with `get`, add with `checked_add` (or `saturating_*` where a wrap is impossible and the line says why), and narrow with `try_from`; an `#[allow]` needs a `reason` and goes on a small function that never sees stored bytes (a float-to-integer cast of a checked value, say).
- Library modules do no file, environment or process access (`clippy.toml` enforces this); a function that must touch the file system says so in its documentation and opts out explicitly, as `compress::oodle::Oodle::load` does.
- Say the byte order, rounding or normalization a function uses in its documentation; file formats differ on exactly those points.
- Every public item has documentation (`missing_docs` is on).
## Releasing
1. Raise the version (a patch, 0.x.Y, for fixes and data or manifest additions; a minor, 0.X.0, for new API or any
breaking change before 1.0; then `cargo check`, so `Cargo.lock` follows) and put the change's CHANGELOG lines under a
`## <version> (<date>)` heading, in one commit.
2. Push it to main. Once every check has passed, release-plz publishes each crate whose version crates.io does not have
yet (trusted publishing: no token is stored anywhere), tags the commit `v<version>` and creates the GitHub Release
with that CHANGELOG section as its notes.
A commit that raises no version only runs CI. Never release by hand.
A new crate's first version can't come from trusted publishing: the token holder publishes it by hand, then adds its
trusted-publishing config (workflow `ci.yml`).
## Reporting a file it cannot read
Open an issue with the "File it cannot read" template. Please include:
- the call that failed and the error message it returned, exactly (it names the offset and what was expected);
- the game and its version or build, and which file or archive entry the bytes came from;
- the first bytes of the stream and its sizes (compressed size, expected output size), as hex;
- the crate version or commit.
Please do **not** attach game files, archives, extracted assets or copyrighted data, and do not paste more than a few dozen bytes of a stream. If a reproduction needs more, we will say what to compute (a hash, a length, a byte count at an offset) rather than ask for the file. Never attach an Oodle library or any other game binary.