diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 176c792d..17063a6f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,28 +60,33 @@ jobs: run: | cp Cargo.lock.msrv Cargo.lock - run: | - cargo test --no-default-features --features rust-backend + cargo test cargo clean -p liblzma -p liblzma-sys - run: | cargo test --features parallel cargo clean -p liblzma -p liblzma-sys - run: | - cargo test --features bindgen + cargo test --no-default-features --features xz-sys + cargo clean -p liblzma -p xz-sys + - run: | + cargo test --no-default-features --features liblzma-sys cargo clean -p liblzma -p liblzma-sys # thin-lto and fat-lto feature required use clang as a linker, but linux default linker is gcc. so exclude thin-lto and fat-lto. - run: | - cargo test --features parallel,static + cargo test --no-default-features --features liblzma-sys,parallel,static cargo clean -p liblzma -p liblzma-sys if: ${{ startsWith(matrix.os, 'ubuntu') }} - run: | - cargo test --all-features + cargo test --test sys_equivalence cargo clean -p liblzma -p liblzma-sys if: ${{ !startsWith(matrix.os, 'ubuntu') }} - run: | - cargo run --manifest-path systest/Cargo.toml + cargo run --manifest-path systest/Cargo.toml --no-default-features --features xz-sys + cargo clean -p xz-sys + cargo run --manifest-path systest/Cargo.toml --no-default-features --features liblzma-sys cargo clean -p liblzma -p liblzma-sys if: matrix.static == 'yes' - - run: cargo run --manifest-path systest/Cargo.toml --features bindgen + - run: cargo run --manifest-path systest/Cargo.toml --no-default-features --features liblzma-sys,bindgen if: matrix.static == 'yes' diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..3189c667 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS + +## Performance Work + +Use the dedicated backend-performance workflow in [`docs/performance-workflow.md`](docs/performance-workflow.md). + +Key entry points: + +- Full deterministic regression gate: `scripts/compare_backends.sh` +- Focused backend workloads: `scripts/compare_workloads.sh` +- High-level API workloads: `scripts/compare_api_workloads.sh` +- Single-backend profiling: `scripts/profile_backend.sh` +- Optimized code inspection: `scripts/inspect_codegen.sh` + +Important constraints: + +- Never compare C and Rust sys backends in the same process. They export the same `lzma_*` symbols. +- Treat `scripts/compare_backends.sh` as the coarse deterministic gate. +- Use `qc` and `size` focused workloads for paths that are property-test-like or otherwise input-sensitive. +- Keep workload shape, iteration count, and profiler command stable while iterating on a hotspot. diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv index 7315c629..4af37940 100644 --- a/Cargo.lock.msrv +++ b/Cargo.lock.msrv @@ -23,6 +23,48 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -41,10 +83,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "bitflags" -version = "1.3.2" +name = "basic-toml" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] [[package]] name = "bumpalo" @@ -70,12 +115,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.4" @@ -202,35 +241,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "ctest2" -version = "0.4.10" +name = "ctest" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf53ed2a9e25d98cd444fd6e73eae7de0a26a8cb9e3f998170c6901a1afa0e5" +checksum = "7dd36db8091f50991402feeb406738b3369ef3b78f0377cd9be8bdb6780424dd" dependencies = [ + "askama", "cc", - "garando_syntax", - "rustc_version", -] - -[[package]] -name = "dirs" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -dependencies = [ - "cfg-if 0.1.10", - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", + "proc-macro2", + "quote", + "syn", + "thiserror", ] [[package]] @@ -279,50 +300,13 @@ dependencies = [ "slab", ] -[[package]] -name = "garando_errors" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18495ec4aced5922809efe4d2862918ff0e8d75e122bde57bba9bae45965256a" -dependencies = [ - "garando_pos", - "libc", - "serde", - "term", - "unicode-xid", -] - -[[package]] -name = "garando_pos" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9386fc75dca486daefbbf5a8d2ea6f379237f95c9b982776159cd66f220aaf" -dependencies = [ - "serde", -] - -[[package]] -name = "garando_syntax" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8a383861d12fc78c251bbcb1ec252dd8338714ce02ab0cc393cfd02f40d32b" -dependencies = [ - "bitflags", - "garando_errors", - "garando_pos", - "log", - "serde", - "serde_json", - "unicode-xid", -] - [[package]] name = "getrandom" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "js-sys", "libc", "wasi", @@ -335,7 +319,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "libc", "r-efi", "wasip2", @@ -347,7 +331,7 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "crunchy", "zerocopy", ] @@ -400,7 +384,7 @@ version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "futures-util", "once_cell", "wasm-bindgen", @@ -418,7 +402,6 @@ version = "0.4.6" dependencies = [ "criterion", "getrandom 0.2.17", - "liblzma-rs-sys", "liblzma-sys", "log", "num_cpus", @@ -426,23 +409,8 @@ dependencies = [ "rand", "regex", "wasm-bindgen-test", -] - -[[package]] -name = "liblzma-rs" -version = "0.1.0" -dependencies = [ - "libc", - "memchr", - "windows-sys", -] - -[[package]] -name = "liblzma-rs-sys" -version = "0.1.0" -dependencies = [ - "libc", - "liblzma-rs", + "xz", + "xz-sys", ] [[package]] @@ -460,15 +428,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" -[[package]] -name = "libredox" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" -dependencies = [ - "libc", -] - [[package]] name = "log" version = "0.4.20" @@ -532,6 +491,21 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "perf-probe" +version = "0.1.0" +dependencies = [ + "liblzma-sys", + "xz", + "xz-sys", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -618,14 +592,13 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -647,15 +620,6 @@ dependencies = [ "getrandom 0.2.17", ] -[[package]] -name = "rand_hc" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b363d4f6370f88d62bf586c80405657bde0f0e1b8945d47d2ad59b906cb4f54" -dependencies = [ - "rand_core", -] - [[package]] name = "rayon" version = "1.11.0" @@ -676,17 +640,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror", -] - [[package]] name = "regex" version = "1.9.0" @@ -717,13 +670,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] -name = "rustc_version" -version = "0.4.1" +name = "rustc-hash" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustversion" @@ -740,12 +690,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -816,36 +760,26 @@ dependencies = [ name = "systest" version = "0.1.0" dependencies = [ - "ctest2", + "ctest", "libc", - "liblzma-rs-sys", "liblzma-sys", -] - -[[package]] -name = "term" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -dependencies = [ - "dirs", - "winapi", + "xz-sys", ] [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -868,12 +802,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "walkdir" version = "2.5.0" @@ -905,7 +833,7 @@ version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" dependencies = [ - "cfg-if 1.0.4", + "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -1003,22 +931,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.11" @@ -1028,12 +940,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-link" version = "0.2.1" @@ -1049,12 +955,38 @@ dependencies = [ "windows-link", ] +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +[[package]] +name = "xz" +version = "0.1.0" +dependencies = [ + "libc", + "memchr", + "windows-sys", +] + +[[package]] +name = "xz-sys" +version = "0.1.0" +dependencies = [ + "libc", + "xz", +] + [[package]] name = "zerocopy" version = "0.8.42" diff --git a/Cargo.toml b/Cargo.toml index 088c1a99..1f1aac90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,18 +17,18 @@ rust-version = "1.63" exclude = [".github/"] [workspace] -members = ["systest", "liblzma-rs", "liblzma-rs-sys"] +members = ["systest", "xz", "xz-sys", "perf-probe"] [dependencies] -# Rust backend (default) - pure Rust implementation -liblzma-sys = { package = "liblzma-rs-sys", path = "liblzma-rs-sys", optional = true } -# C backend - original liblzma C library via FFI -liblzma-c-sys = { package = "liblzma-sys", path = "liblzma-sys", version = "0.4.5", optional = true, default-features = false } +xz = { path = "xz", optional = true } +xz-sys = { path = "xz-sys", optional = true } +liblzma-sys = { path = "liblzma-sys", version = "0.4.5", optional = true, default-features = false } num_cpus = { version = "1.16.0", optional = true } criterion = { version = "0.5", features = ["html_reports"], optional = true } [dev-dependencies] -rand = "=0.8.0" +rand = "0.8.0" +quickcheck = "=1.0.1" regex = "=1.9.0" log = "=0.4.20" @@ -41,25 +41,26 @@ required-features = ["bench"] getrandom = { version = "0.2", features = ["js"] } [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] -quickcheck = "=1.0.1" +xz-sys = { path = "xz-sys" } +liblzma-sys = { path = "liblzma-sys" } [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3" [features] -default = ["rust-backend"] -rust-backend = ["liblzma-sys"] -c-backend = ["liblzma-c-sys/bindgen"] -static = ["liblzma-c-sys?/static"] -parallel = ["liblzma-sys?/parallel", "liblzma-c-sys?/parallel", "num_cpus"] -bindgen = ["liblzma-c-sys?/bindgen"] # ignored for rust-backend -wasm = ["liblzma-sys?/wasm", "liblzma-c-sys?/wasm"] -uncheck_liblzma_version = ["liblzma-c-sys?/uncheck_liblzma_version"] # ignored for rust-backend +default = ["xz"] +xz = ["dep:xz"] +xz-sys = ["dep:xz-sys"] +liblzma-sys = ["dep:liblzma-sys", "liblzma-sys/bindgen"] +static = ["liblzma-sys?/static"] +parallel = ["xz-sys?/parallel", "liblzma-sys?/parallel", "num_cpus"] +bindgen = ["liblzma-sys?/bindgen"] # only affects liblzma-sys +wasm = ["xz-sys?/wasm", "liblzma-sys?/wasm"] +uncheck_liblzma_version = ["liblzma-sys?/uncheck_liblzma_version"] # only affects liblzma-sys bench = ["criterion"] -# These two are for cross-language LTO with the C backend. -# Ignored for rust-backend. -fat-lto = ["liblzma-c-sys?/fat-lto"] -thin-lto = ["liblzma-c-sys?/thin-lto"] +# These two are for cross-language LTO with liblzma-sys. +fat-lto = ["liblzma-sys?/fat-lto"] +thin-lto = ["liblzma-sys?/thin-lto"] [package.metadata.docs.rs] features = ["parallel"] diff --git a/README.md b/README.md index 990909fe..4ec14149 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,16 @@ so you can migrate simply. - XZ upgraded to 5.8 - Dropped `tokio` support (If you need async I/O, use [`async-compression`](https://github.com/Nullus157/async-compression) crate with `lzma` feature flag) +## Backend selection + +The default build uses the pure Rust backend via `xz-sys`. + +Use the original C backend only when you explicitly opt into it: + +```toml +liblzma = { version = "0.4", default-features = false, features = ["liblzma-sys"] } +``` + ## License This project is licensed under either of diff --git a/benches/backend_comparison.rs b/benches/backend_comparison.rs index ee3c4130..bb9c6bed 100644 --- a/benches/backend_comparison.rs +++ b/benches/backend_comparison.rs @@ -4,8 +4,41 @@ use std::ptr; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; -use liblzma_c_sys as c_sys; -use liblzma_sys as rs_sys; +#[cfg(any( + all(feature = "xz", feature = "xz-sys"), + all(feature = "xz", feature = "liblzma-sys"), + all(feature = "xz-sys", feature = "liblzma-sys"), +))] +compile_error!("backend_comparison bench must be built with exactly one backend feature"); +#[cfg(not(any(feature = "xz", feature = "xz-sys", feature = "liblzma-sys")))] +compile_error!("backend_comparison bench requires `xz`, `xz-sys`, or `liblzma-sys`"); + +#[cfg(feature = "liblzma-sys")] +use liblzma_sys::{ + lzma_crc32, lzma_crc64, lzma_easy_buffer_encode, lzma_stream_buffer_bound, + lzma_stream_buffer_decode, LZMA_CHECK_CRC64, +}; +#[cfg(feature = "xz")] +use xz::check::{crc32_fast::lzma_crc32, crc64_fast::lzma_crc64}; +#[cfg(feature = "xz")] +use xz::common::{ + easy_buffer_encoder::lzma_easy_buffer_encode, stream_buffer_decoder::lzma_stream_buffer_decode, + stream_buffer_encoder::lzma_stream_buffer_bound, +}; +#[cfg(feature = "xz")] +use xz::types::LZMA_CHECK_CRC64; +#[cfg(feature = "xz-sys")] +use xz_sys::{ + lzma_crc32, lzma_crc64, lzma_easy_buffer_encode, lzma_stream_buffer_bound, + lzma_stream_buffer_decode, LZMA_CHECK_CRC64, +}; + +#[cfg(feature = "xz")] +const BACKEND_NAME: &str = "xz"; +#[cfg(feature = "liblzma-sys")] +const BACKEND_NAME: &str = "liblzma-sys"; +#[cfg(feature = "xz-sys")] +const BACKEND_NAME: &str = "xz-sys"; fn make_payload(size: usize) -> Vec { let mut x: u64 = 0x9E3779B97F4A7C15; @@ -19,13 +52,13 @@ fn make_payload(size: usize) -> Vec { out } -unsafe fn c_encode(input: &[u8]) -> Vec { - let bound = c_sys::lzma_stream_buffer_bound(input.len()); +unsafe fn backend_encode(input: &[u8]) -> Vec { + let bound = lzma_stream_buffer_bound(input.len()); let mut out = vec![0u8; bound]; let mut out_pos: usize = 0; - c_sys::lzma_easy_buffer_encode( + lzma_easy_buffer_encode( 6, - c_sys::LZMA_CHECK_CRC64, + LZMA_CHECK_CRC64, ptr::null(), input.as_ptr(), input.len(), @@ -37,50 +70,12 @@ unsafe fn c_encode(input: &[u8]) -> Vec { out } -unsafe fn rs_encode(input: &[u8]) -> Vec { - let bound = rs_sys::lzma_stream_buffer_bound(input.len()); - let mut out = vec![0u8; bound]; - let mut out_pos: usize = 0; - rs_sys::lzma_easy_buffer_encode( - 6, - rs_sys::LZMA_CHECK_CRC64, - ptr::null(), - input.as_ptr(), - input.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - out.truncate(out_pos); - out -} - -unsafe fn c_decode(compressed: &[u8], out_size: usize) -> Vec { - let mut out = vec![0u8; out_size]; - let mut memlimit = u64::MAX; - let mut in_pos = 0usize; - let mut out_pos = 0usize; - c_sys::lzma_stream_buffer_decode( - &mut memlimit, - 0, - ptr::null(), - compressed.as_ptr(), - &mut in_pos, - compressed.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - out.truncate(out_pos); - out -} - -unsafe fn rs_decode(compressed: &[u8], out_size: usize) -> Vec { +unsafe fn backend_decode(compressed: &[u8], out_size: usize) -> Vec { let mut out = vec![0u8; out_size]; let mut memlimit = u64::MAX; let mut in_pos = 0usize; let mut out_pos = 0usize; - rs_sys::lzma_stream_buffer_decode( + lzma_stream_buffer_decode( &mut memlimit, 0, ptr::null(), @@ -103,11 +98,8 @@ fn bench_encode(c: &mut Criterion) { let input = make_payload(size); group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input(BenchmarkId::new("c", label), &input, |b, input| { - b.iter(|| unsafe { c_encode(black_box(input)) }) - }); - group.bench_with_input(BenchmarkId::new("rust", label), &input, |b, input| { - b.iter(|| unsafe { rs_encode(black_box(input)) }) + group.bench_with_input(BenchmarkId::new(BACKEND_NAME, label), &input, |b, input| { + b.iter(|| unsafe { backend_encode(black_box(input)) }) }); } group.finish(); @@ -119,17 +111,13 @@ fn bench_decode(c: &mut Criterion) { let mut group = c.benchmark_group("decode"); for &(size, label) in sizes { let input = make_payload(size); - let c_compressed = unsafe { c_encode(&input) }; - let rs_compressed = unsafe { rs_encode(&input) }; + let compressed = unsafe { backend_encode(&input) }; group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input(BenchmarkId::new("c", label), &c_compressed, |b, data| { - b.iter(|| unsafe { c_decode(black_box(data), size) }) - }); group.bench_with_input( - BenchmarkId::new("rust", label), - &rs_compressed, - |b, data| b.iter(|| unsafe { rs_decode(black_box(data), size) }), + BenchmarkId::new(BACKEND_NAME, label), + &compressed, + |b, data| b.iter(|| unsafe { backend_decode(black_box(data), size) }), ); } group.finish(); @@ -143,11 +131,8 @@ fn bench_crc32(c: &mut Criterion) { let data = make_payload(size); group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input(BenchmarkId::new("c", label), &data, |b, data| { - b.iter(|| unsafe { c_sys::lzma_crc32(black_box(data.as_ptr()), data.len(), 0) }) - }); - group.bench_with_input(BenchmarkId::new("rust", label), &data, |b, data| { - b.iter(|| unsafe { rs_sys::lzma_crc32(black_box(data.as_ptr()), data.len(), 0) }) + group.bench_with_input(BenchmarkId::new(BACKEND_NAME, label), &data, |b, data| { + b.iter(|| unsafe { lzma_crc32(black_box(data.as_ptr()), data.len(), 0) }) }); } group.finish(); @@ -161,11 +146,8 @@ fn bench_crc64(c: &mut Criterion) { let data = make_payload(size); group.throughput(Throughput::Bytes(size as u64)); - group.bench_with_input(BenchmarkId::new("c", label), &data, |b, data| { - b.iter(|| unsafe { c_sys::lzma_crc64(black_box(data.as_ptr()), data.len(), 0) }) - }); - group.bench_with_input(BenchmarkId::new("rust", label), &data, |b, data| { - b.iter(|| unsafe { rs_sys::lzma_crc64(black_box(data.as_ptr()), data.len(), 0) }) + group.bench_with_input(BenchmarkId::new(BACKEND_NAME, label), &data, |b, data| { + b.iter(|| unsafe { lzma_crc64(black_box(data.as_ptr()), data.len(), 0) }) }); } group.finish(); diff --git a/docs/performance-workflow.md b/docs/performance-workflow.md new file mode 100644 index 00000000..398138dc --- /dev/null +++ b/docs/performance-workflow.md @@ -0,0 +1,151 @@ +# Performance Workflow + +This repository now has a repeatable loop for backend comparison, profiling, and code generation inspection. + +Important: the C and Rust sys backends must never be linked into the same process when comparing performance. Both export the same `lzma_*` symbols, so shared-process comparisons can silently resolve to the wrong implementation. + +The root crate now has three backend modes: + +- `xz`: direct Rust ABI calls into the pure Rust port +- `xz-sys`: C ABI calls into the pure Rust port through the `xz-sys` shell +- `liblzma-sys`: C ABI calls into vendored C `liblzma` + +The comparison scripts in this document force the C backend to build from the vendored +`liblzma-sys/xz` source tree by setting `LZMA_API_STATIC=1`. This avoids silently +benchmarking a system `liblzma` from `pkg-config`, which would make the C/Rust +comparison depend on host packaging and compiler choices instead of the ported source. + +## 1. Baseline correctness + +Keep correctness green before taking timings: + +```bash +cargo test +cargo test --no-default-features --features xz-sys +cargo test --no-default-features --features liblzma-sys +cargo test --test sys_equivalence +``` + +## 2. Compare the full test suite + +Use `hyperfine` to compare end-to-end wall clock time of the deterministic root test bundle (`xz` vs C) and `systest` with isolated target directories per backend: + +```bash +scripts/compare_backends.sh --runs 10 --warmup 2 +``` + +This writes: + +- `target/perf-results/root-tests.json` +- `target/perf-results/root-tests.md` +- `target/perf-results/systest.json` +- `target/perf-results/systest.md` + +Those reports are the coarse regression gate. Run them after major porting or optimization work. + +The root bundle intentionally skips QuickCheck-based unit tests because they generate different random inputs in separate backend processes. Cover those property-style paths with the focused `qc` and `size` workloads instead. + +## 3. Compare focused workloads + +Use `perf-probe`, a small standalone binary crate that links exactly one backend at a time. The comparison scripts use the direct `xz` backend by default; `xz-sys` remains available for ABI-shell checks. + +Examples: + +```bash +scripts/compare_workloads.sh encode --input-kind random --size 1048576 --iters 20 --warmup 3 +scripts/compare_workloads.sh decode --input-kind random --size 1048576 --iters 50 --warmup 5 +scripts/compare_workloads.sh size --input-kind random --size 1048576 --iters 400 --warmup 40 +scripts/compare_workloads.sh crc64 --size 16777216 --iters 400 --warmup 20 +scripts/compare_workloads.sh crc64 --size 1048576 --chunk-size 16 --iters 400 --warmup 40 +``` + +This writes workload-specific `hyperfine` reports under `target/perf-results/`. + +For tiny inputs, increase `--iters` until one benchmarked command takes at least around a +second. Otherwise process startup noise can dominate the comparison even when the actual +backend work is near parity. + +There is still a criterion bench in [`benches/backend_comparison.rs`](../benches/backend_comparison.rs), but it now measures one backend per run. Use it only with exactly one backend feature enabled. + +For high-level API regressions, compare the root crate against the upstream XZ corpus: + +```bash +scripts/compare_api_workloads.sh standard-files --mode all --iters 200 --warmup 20 +scripts/compare_api_workloads.sh standard-files --mode good --iters 400 --warmup 40 +scripts/compare_api_workloads.sh standard-files --mode good --name-pattern delta --iters 400 --warmup 40 +scripts/compare_api_workloads.sh qc --mode both --cases 128 --max-size 4096 --iters 200 --warmup 20 +scripts/compare_api_workloads.sh bufread-trailing --mode both --input-size 1024 --trailing-size 123 --iters 1000 --warmup 100 +``` + +This uses [`examples/standard_files_probe.rs`](../examples/standard_files_probe.rs), which mirrors the `tests/xz.rs` `standard_files` path and writes reports to: + +- `target/perf-results/api-standard-files.json` +- `target/perf-results/api-standard-files.md` + +The `qc` workload uses [`examples/qc_probe.rs`](../examples/qc_probe.rs) to reproduce the +small-input repeated round-trip pattern from the root crate tests. This is useful when +overall regressions show up in `root-tests` even though large encode/decode probes look +good. + +The `bufread-trailing` workload uses +[`examples/bufread_trailing_probe.rs`](../examples/bufread_trailing_probe.rs) to reproduce +the `bufread::tests::compressed_and_trailing_data` path with enough in-process repetition +to reduce test process startup noise. + +The `size` workload isolates the `uncompressed_size()` path from [`src/lib.rs`](../src/lib.rs), +which corresponds to the QuickCheck-based `tests::size` unit test but with deterministic input. + +Use `--name-pattern ` to isolate a file family inside the XZ corpus when a full-corpus comparison is too mixed to identify the remaining gap. + +## 4. Profile a focused workload + +`perf-probe` is a profiler-friendly executable that runs a single workload many times with deterministic input. + +Examples: + +```bash +scripts/profile_backend.sh xz decode --size 1048576 --iters 800 --warmup 80 +scripts/profile_backend.sh xz size --input-kind random --size 1048576 --iters 800 --warmup 80 +scripts/profile_backend.sh xz encode --input-kind random --size 8388608 --iters 150 --warmup 20 +scripts/profile_backend.sh c crc64 --size 16777216 --iters 400 +``` + +Useful flags passed through to `perf-probe`: + +- `--workload encode|decode|size|crc32|crc64` +- `--input ` +- `--compressed-input ` +- `--save-output ` +- `--input-kind text|random` +- `--size ` +- `--chunk-size ` +- `--expected-size ` +- `--iters ` +- `--warmup ` +- `--preset ` + +On macOS the script prefers `samply`; on Linux it falls back to `perf`; otherwise it runs the workload plainly with release debuginfo enabled. + +## 5. Inspect the generated code + +After a profile points to a hot Rust function, inspect its optimized output: + +```bash +scripts/inspect_codegen.sh xz::lzma::lzma_encoder::lzma_encode --package xz +scripts/inspect_codegen.sh xz::check::crc64_fast::lzma_crc64 --package xz --format llvm +``` + +This uses `cargo-asm` and builds under `target/codegen` by default. + +## 6. Iterate + +The expected loop is: + +1. Reproduce the gap with `scripts/compare_backends.sh`. +2. Use `scripts/compare_workloads.sh` to isolate the subsystem. +3. Capture a focused profile with `scripts/profile_backend.sh`. +4. Pick the hottest Rust function from the profile. +5. Inspect its assembly or LLVM IR with `scripts/inspect_codegen.sh`. +6. Change the Rust port, then repeat the same commands. + +Keep the input shape, iteration count, and profiler command stable while working a hotspot so before/after numbers stay comparable. diff --git a/examples/bufread_trailing_probe.rs b/examples/bufread_trailing_probe.rs new file mode 100644 index 00000000..fd02454d --- /dev/null +++ b/examples/bufread_trailing_probe.rs @@ -0,0 +1,281 @@ +use std::env; +use std::io::Read; +use std::time::{Duration, Instant}; + +use liblzma::bufread; + +#[cfg(feature = "xz")] +const BACKEND_NAME: &str = "xz"; +#[cfg(feature = "xz-sys")] +const BACKEND_NAME: &str = "xz-sys"; +#[cfg(feature = "liblzma-sys")] +const BACKEND_NAME: &str = "liblzma-sys"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Mode { + Encode, + Decode, + Both, +} + +#[derive(Debug)] +struct Config { + mode: Mode, + input_size: usize, + trailing_size: usize, + level: u32, + iters: usize, + warmup: usize, +} + +#[derive(Debug)] +struct Measurement { + elapsed: Duration, + throughput_mib_s: f64, + digest: u64, +} + +#[inline(always)] +fn black_box(value: T) -> T { + let value = std::mem::ManuallyDrop::new(value); + unsafe { std::ptr::read_volatile(&*value) } +} + +fn main() { + let config = Config::parse(env::args().skip(1)).unwrap_or_else(|message| { + eprintln!("{message}"); + std::process::exit(2); + }); + let input = build_input(config.input_size); + let trailing = build_trailing(config.trailing_size); + let decode_case = build_decode_case(&input, &trailing, config.level); + + println!( + "config: backend={} mode={:?} input_size={} trailing_size={} level={} iters={} warmup={}", + BACKEND_NAME, + config.mode, + config.input_size, + config.trailing_size, + config.level, + config.iters, + config.warmup + ); + + let bytes_per_iter = match config.mode { + Mode::Encode => input.len(), + Mode::Decode => input.len() + trailing.len(), + Mode::Both => input.len() * 2 + trailing.len(), + }; + let measurement = measure(bytes_per_iter, config.iters, config.warmup, || { + run_case( + black_box(&input), + black_box(&trailing), + black_box(&decode_case), + config.mode, + config.level, + ) + }); + print_measurement(&measurement, config.iters); +} + +impl Config { + fn parse(mut args: I) -> Result + where + I: Iterator, + { + let mut config = Self { + mode: Mode::Both, + input_size: 1024, + trailing_size: 123, + level: 6, + iters: 1000, + warmup: 100, + }; + + while let Some(arg) = args.next() { + match arg.as_str() { + "--mode" => { + config.mode = parse_mode(next_arg(&mut args, "--mode")?)?; + } + "--input-size" => { + config.input_size = + parse_usize(next_arg(&mut args, "--input-size")?, "--input-size")?; + } + "--trailing-size" => { + config.trailing_size = + parse_usize(next_arg(&mut args, "--trailing-size")?, "--trailing-size")?; + } + "--level" => { + config.level = parse_u32(next_arg(&mut args, "--level")?, "--level")?; + } + "--iters" => { + config.iters = parse_usize(next_arg(&mut args, "--iters")?, "--iters")?; + } + "--warmup" => { + config.warmup = parse_usize(next_arg(&mut args, "--warmup")?, "--warmup")?; + } + "--help" | "-h" => return Err(usage()), + unknown => return Err(format!("unknown argument `{unknown}`\n\n{}", usage())), + } + } + + if config.input_size == 0 { + return Err("`--input-size` must be greater than zero".to_owned()); + } + if config.iters == 0 { + return Err("`--iters` must be greater than zero".to_owned()); + } + + Ok(config) + } +} + +fn usage() -> String { + let mut message = String::new(); + message.push_str("Usage:\n"); + message.push_str( + " cargo run --example bufread_trailing_probe --release -- [options]\n\ + \n\ + To use the C backend instead:\n\ + cargo run --example bufread_trailing_probe --release --no-default-features --features liblzma-sys -- [options]\n\n", + ); + message.push_str("Options:\n"); + message.push_str(" --mode \n"); + message.push_str(" --input-size \n"); + message.push_str(" --trailing-size \n"); + message.push_str(" --level \n"); + message.push_str(" --iters \n"); + message.push_str(" --warmup \n"); + message +} + +fn next_arg(args: &mut I, flag: &str) -> Result +where + I: Iterator, +{ + args.next() + .ok_or_else(|| format!("missing value for `{flag}`\n\n{}", usage())) +} + +fn parse_mode(value: String) -> Result { + match value.as_str() { + "encode" => Ok(Mode::Encode), + "decode" => Ok(Mode::Decode), + "both" => Ok(Mode::Both), + _ => Err(format!("unsupported mode `{value}`")), + } +} + +fn parse_usize(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as usize: `{value}`")) +} + +fn parse_u32(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as u32: `{value}`")) +} + +fn build_input(len: usize) -> Vec { + (0..len).map(|num| num as u8).collect() +} + +fn build_trailing(len: usize) -> Vec { + (0..len).map(|num| ((25 + num) % 256) as u8).collect() +} + +fn build_decode_case(input: &[u8], trailing: &[u8], level: u32) -> Vec { + let mut encoder = bufread::XzEncoder::new(input, level); + let mut decoder_input = Vec::new(); + encoder.read_to_end(&mut decoder_input).unwrap(); + decoder_input.extend_from_slice(trailing); + decoder_input +} + +fn run_case(input: &[u8], trailing: &[u8], decode_case: &[u8], mode: Mode, level: u32) -> u64 { + match mode { + Mode::Encode => run_encode_case(input, level), + Mode::Decode => run_decode_case(input, trailing, decode_case), + Mode::Both => { + let encoded = run_encode_to_vec(input, level); + let mut decode_input = Vec::with_capacity(encoded.len() + trailing.len()); + decode_input.extend_from_slice(&encoded); + decode_input.extend_from_slice(trailing); + fold_bytes(encoded.len(), &encoded) ^ run_decode_case(input, trailing, &decode_input) + } + } +} + +fn run_encode_case(input: &[u8], level: u32) -> u64 { + let encoded = run_encode_to_vec(input, level); + fold_bytes(encoded.len(), &encoded) +} + +fn run_encode_to_vec(input: &[u8], level: u32) -> Vec { + let mut encoder = bufread::XzEncoder::new(input, level); + let mut encoded = Vec::new(); + encoder.read_to_end(&mut encoded).unwrap(); + encoded +} + +fn run_decode_case(input: &[u8], trailing: &[u8], decode_case: &[u8]) -> u64 { + let mut decoder_reader = decode_case; + let mut decoder = bufread::XzDecoder::new(&mut decoder_reader); + let mut decompressed = vec![0u8; input.len()]; + let read = decoder.read(&mut decompressed).unwrap(); + assert_eq!(read, input.len()); + assert_eq!(decompressed, input); + assert_eq!(decoder.total_out(), input.len() as u64); + + let mut remaining = Vec::new(); + let trailing_read = decoder_reader.read_to_end(&mut remaining).unwrap(); + assert_eq!(trailing_read, trailing.len()); + assert_eq!(remaining, trailing); + + fold_bytes(input.len() + remaining.len(), &decompressed) + ^ fold_bytes(remaining.len(), &remaining) +} + +fn measure(bytes_per_iter: usize, iters: usize, warmup: usize, mut work: F) -> Measurement +where + F: FnMut() -> u64, +{ + let mut digest = 0u64; + for _ in 0..warmup { + digest ^= black_box(work()); + } + + let start = Instant::now(); + for _ in 0..iters { + digest ^= black_box(work()); + } + let elapsed = start.elapsed(); + let mib = (bytes_per_iter as f64 * iters as f64) / (1024.0 * 1024.0); + + Measurement { + elapsed, + throughput_mib_s: mib / elapsed.as_secs_f64(), + digest, + } +} + +fn print_measurement(measurement: &Measurement, iters: usize) { + println!( + "{}: total={:.3?} ns_per_iter={:.0} throughput_mib_s={:.2} digest={:#x}", + BACKEND_NAME, + measurement.elapsed, + measurement.elapsed.as_nanos() as f64 / iters as f64, + measurement.throughput_mib_s, + measurement.digest + ); +} + +fn fold_bytes(len: usize, data: &[u8]) -> u64 { + let mut acc = len as u64; + for &byte in data.iter().take(32) { + acc = acc.rotate_left(5) ^ u64::from(byte); + } + acc +} diff --git a/examples/qc_probe.rs b/examples/qc_probe.rs new file mode 100644 index 00000000..678cfa0d --- /dev/null +++ b/examples/qc_probe.rs @@ -0,0 +1,270 @@ +use std::env; +use std::io::{Read, Write}; +use std::time::{Duration, Instant}; + +use liblzma::read; +use liblzma::write; + +#[cfg(feature = "xz")] +const BACKEND_NAME: &str = "xz"; +#[cfg(feature = "xz-sys")] +const BACKEND_NAME: &str = "xz-sys"; +#[cfg(feature = "liblzma-sys")] +const BACKEND_NAME: &str = "liblzma-sys"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Mode { + Read, + Write, + Both, +} + +#[derive(Debug)] +struct Config { + mode: Mode, + cases: usize, + max_size: usize, + seed: u64, + iters: usize, + warmup: usize, +} + +#[derive(Debug)] +struct Measurement { + elapsed: Duration, + throughput_mib_s: f64, + digest: u64, +} + +#[inline(always)] +fn black_box(value: T) -> T { + let value = std::mem::ManuallyDrop::new(value); + unsafe { std::ptr::read_volatile(&*value) } +} + +fn main() { + let config = Config::parse(env::args().skip(1)).unwrap_or_else(|message| { + eprintln!("{message}"); + std::process::exit(2); + }); + let cases = build_cases(config.cases, config.max_size, config.seed); + let total_bytes: usize = cases.iter().map(Vec::len).sum(); + + println!( + "config: backend={} mode={:?} cases={} max_size={} bytes={} seed={} iters={} warmup={}", + BACKEND_NAME, + config.mode, + cases.len(), + config.max_size, + total_bytes, + config.seed, + config.iters, + config.warmup + ); + + let bytes_per_iter = total_bytes + * match config.mode { + Mode::Read | Mode::Write => 1, + Mode::Both => 2, + }; + let measurement = measure(bytes_per_iter, config.iters, config.warmup, || { + run_cases(black_box(&cases), config.mode) + }); + print_measurement(&measurement, config.iters); +} + +impl Config { + fn parse(mut args: I) -> Result + where + I: Iterator, + { + let mut config = Self { + mode: Mode::Both, + cases: 128, + max_size: 4096, + seed: 0xC0DEC0FFEE, + iters: 200, + warmup: 20, + }; + + while let Some(arg) = args.next() { + match arg.as_str() { + "--mode" => { + config.mode = parse_mode(next_arg(&mut args, "--mode")?)?; + } + "--cases" => { + config.cases = parse_usize(next_arg(&mut args, "--cases")?, "--cases")?; + } + "--max-size" => { + config.max_size = + parse_usize(next_arg(&mut args, "--max-size")?, "--max-size")?; + } + "--seed" => { + config.seed = parse_u64(next_arg(&mut args, "--seed")?, "--seed")?; + } + "--iters" => { + config.iters = parse_usize(next_arg(&mut args, "--iters")?, "--iters")?; + } + "--warmup" => { + config.warmup = parse_usize(next_arg(&mut args, "--warmup")?, "--warmup")?; + } + "--help" | "-h" => return Err(usage()), + unknown => return Err(format!("unknown argument `{unknown}`\n\n{}", usage())), + } + } + + if config.cases == 0 { + return Err("`--cases` must be greater than zero".to_owned()); + } + if config.max_size == 0 { + return Err("`--max-size` must be greater than zero".to_owned()); + } + if config.iters == 0 { + return Err("`--iters` must be greater than zero".to_owned()); + } + + Ok(config) + } +} + +fn usage() -> String { + let mut message = String::new(); + message.push_str("Usage:\n"); + message.push_str( + " cargo run --example qc_probe --release -- [options]\n\ + \n\ + To use the C backend instead:\n\ + cargo run --example qc_probe --release --no-default-features --features liblzma-sys -- [options]\n\n", + ); + message.push_str("Options:\n"); + message.push_str(" --mode \n"); + message.push_str(" --cases \n"); + message.push_str(" --max-size \n"); + message.push_str(" --seed \n"); + message.push_str(" --iters \n"); + message.push_str(" --warmup \n"); + message +} + +fn next_arg(args: &mut I, flag: &str) -> Result +where + I: Iterator, +{ + args.next() + .ok_or_else(|| format!("missing value for `{flag}`\n\n{}", usage())) +} + +fn parse_mode(value: String) -> Result { + match value.as_str() { + "read" => Ok(Mode::Read), + "write" => Ok(Mode::Write), + "both" => Ok(Mode::Both), + _ => Err(format!("unsupported mode `{value}`")), + } +} + +fn parse_usize(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as usize: `{value}`")) +} + +fn parse_u64(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as u64: `{value}`")) +} + +fn build_cases(count: usize, max_size: usize, seed: u64) -> Vec> { + let mut rng = seed; + let mut cases = Vec::with_capacity(count); + for i in 0..count { + rng = next_u64(rng); + let len = 1 + ((rng as usize ^ i.wrapping_mul(131)) % max_size); + let mut case = Vec::with_capacity(len); + for _ in 0..len { + rng = next_u64(rng); + case.push((rng >> 56) as u8); + } + cases.push(case); + } + cases +} + +fn next_u64(mut x: u64) -> u64 { + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + x.wrapping_mul(0x2545F4914F6CDD1D) +} + +fn run_cases(cases: &[Vec], mode: Mode) -> u64 { + let mut digest = 0u64; + for case in cases { + digest = digest.rotate_left(7) + ^ match mode { + Mode::Read => run_read_case(case), + Mode::Write => run_write_case(case), + Mode::Both => run_read_case(case) ^ run_write_case(case), + }; + } + digest +} + +fn run_read_case(input: &[u8]) -> u64 { + let reader = read::XzEncoder::new(input, 6); + let mut decoder = read::XzDecoder::new(reader); + let mut output = Vec::with_capacity(input.len()); + decoder.read_to_end(&mut output).unwrap(); + fold_bytes(output.len(), &output) +} + +fn run_write_case(input: &[u8]) -> u64 { + let inner = write::XzDecoder::new(Vec::with_capacity(input.len())); + let mut encoder = write::XzEncoder::new(inner, 6); + encoder.write_all(input).unwrap(); + let output = encoder.finish().unwrap().finish().unwrap(); + fold_bytes(output.len(), &output) +} + +fn measure(bytes_per_iter: usize, iters: usize, warmup: usize, mut work: F) -> Measurement +where + F: FnMut() -> u64, +{ + let mut digest = 0u64; + for _ in 0..warmup { + digest ^= black_box(work()); + } + + let start = Instant::now(); + for _ in 0..iters { + digest ^= black_box(work()); + } + let elapsed = start.elapsed(); + let mib = (bytes_per_iter as f64 * iters as f64) / (1024.0 * 1024.0); + + Measurement { + elapsed, + throughput_mib_s: mib / elapsed.as_secs_f64(), + digest, + } +} + +fn print_measurement(measurement: &Measurement, iters: usize) { + println!( + "{}: total={:.3?} ns_per_iter={:.0} throughput_mib_s={:.2} digest={:#x}", + BACKEND_NAME, + measurement.elapsed, + measurement.elapsed.as_nanos() as f64 / iters as f64, + measurement.throughput_mib_s, + measurement.digest + ); +} + +fn fold_bytes(len: usize, data: &[u8]) -> u64 { + let mut acc = len as u64; + for &byte in data.iter().take(32) { + acc = acc.rotate_left(5) ^ u64::from(byte); + } + acc +} diff --git a/examples/standard_files_probe.rs b/examples/standard_files_probe.rs new file mode 100644 index 00000000..816ca9b3 --- /dev/null +++ b/examples/standard_files_probe.rs @@ -0,0 +1,341 @@ +use std::env; +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::path::PathBuf; +use std::time::{Duration, Instant}; + +use liblzma::read; +use liblzma::stream; +use liblzma::write; + +#[cfg(feature = "xz")] +const BACKEND_NAME: &str = "xz"; +#[cfg(feature = "xz-sys")] +const BACKEND_NAME: &str = "xz-sys"; +#[cfg(feature = "liblzma-sys")] +const BACKEND_NAME: &str = "liblzma-sys"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Mode { + All, + Good, + Bad, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Phase { + Both, + Read, + Write, +} + +#[derive(Debug)] +struct Config { + corpus_dir: PathBuf, + mode: Mode, + phase: Phase, + name_pattern: Option, + iters: usize, + warmup: usize, +} + +#[derive(Debug)] +struct Case { + name: String, + data: Vec, + is_bad: bool, + decoded: Option>, +} + +#[derive(Debug)] +struct Measurement { + elapsed: Duration, + throughput_mib_s: f64, + digest: u64, +} + +#[inline(always)] +fn black_box(value: T) -> T { + let value = std::mem::ManuallyDrop::new(value); + unsafe { std::ptr::read_volatile(&*value) } +} + +fn main() { + let config = Config::parse(env::args().skip(1)).unwrap_or_else(|message| { + eprintln!("{message}"); + std::process::exit(2); + }); + let cases = load_cases(&config).unwrap_or_else(|err| { + eprintln!("failed to load corpus: {err}"); + std::process::exit(1); + }); + let total_bytes: usize = cases.iter().map(|case| case.data.len()).sum(); + + println!( + "config: backend={} mode={:?} phase={:?} cases={} bytes={} iters={} warmup={}", + BACKEND_NAME, + config.mode, + config.phase, + cases.len(), + total_bytes, + config.iters, + config.warmup + ); + if let Some(pattern) = &config.name_pattern { + println!("name_pattern: {pattern}"); + } + if !cases.is_empty() { + let case_names = cases + .iter() + .map(|case| case.name.as_str()) + .collect::>() + .join(","); + println!("cases: {case_names}"); + } + + let measurement = measure(total_bytes, config.iters, config.warmup, || { + run_cases(black_box(&cases), config.phase) + }); + print_measurement(&measurement, config.iters); +} + +impl Config { + fn parse(mut args: I) -> Result + where + I: Iterator, + { + let mut config = Self { + corpus_dir: PathBuf::from("liblzma-sys/xz/tests/files"), + mode: Mode::All, + phase: Phase::Both, + name_pattern: None, + iters: 200, + warmup: 20, + }; + + while let Some(arg) = args.next() { + match arg.as_str() { + "--corpus-dir" => { + config.corpus_dir = PathBuf::from(next_arg(&mut args, "--corpus-dir")?); + } + "--mode" => { + config.mode = parse_mode(next_arg(&mut args, "--mode")?)?; + } + "--phase" => { + config.phase = parse_phase(next_arg(&mut args, "--phase")?)?; + } + "--name-pattern" => { + config.name_pattern = Some(next_arg(&mut args, "--name-pattern")?); + } + "--iters" => { + config.iters = parse_usize(next_arg(&mut args, "--iters")?, "--iters")?; + } + "--warmup" => { + config.warmup = parse_usize(next_arg(&mut args, "--warmup")?, "--warmup")?; + } + "--help" | "-h" => return Err(usage()), + unknown => return Err(format!("unknown argument `{unknown}`\n\n{}", usage())), + } + } + + if config.iters == 0 { + return Err("`--iters` must be greater than zero".to_owned()); + } + + Ok(config) + } +} + +fn usage() -> String { + let mut message = String::new(); + message.push_str("Usage:\n"); + message.push_str( + " cargo run --example standard_files_probe --release -- [options]\n\ + \n\ + To use the C backend instead:\n\ + cargo run --example standard_files_probe --release --no-default-features --features liblzma-sys -- [options]\n\n", + ); + message.push_str("Options:\n"); + message.push_str(" --corpus-dir XZ test corpus directory\n"); + message.push_str(" --mode \n"); + message.push_str(" --phase \n"); + message.push_str(" --name-pattern \n"); + message.push_str(" --iters \n"); + message.push_str(" --warmup \n"); + message +} + +fn next_arg(args: &mut I, flag: &str) -> Result +where + I: Iterator, +{ + args.next() + .ok_or_else(|| format!("missing value for `{flag}`\n\n{}", usage())) +} + +fn parse_usize(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as usize: `{value}`")) +} + +fn parse_mode(value: String) -> Result { + match value.as_str() { + "all" => Ok(Mode::All), + "good" => Ok(Mode::Good), + "bad" => Ok(Mode::Bad), + _ => Err(format!("unsupported mode `{value}`")), + } +} + +fn parse_phase(value: String) -> Result { + match value.as_str() { + "both" => Ok(Phase::Both), + "read" => Ok(Phase::Read), + "write" => Ok(Phase::Write), + _ => Err(format!("unsupported phase `{value}`")), + } +} + +fn load_cases(config: &Config) -> Result, std::io::Error> { + let mut cases = Vec::new(); + for entry in fs::read_dir(&config.corpus_dir)? { + let entry = entry?; + let path = entry.path(); + if path.extension().and_then(|s| s.to_str()) != Some("xz") { + continue; + } + + let filename = entry.file_name().into_string().unwrap(); + if filename.contains("unsupported-check") { + continue; + } + if let Some(pattern) = &config.name_pattern { + if !filename.contains(pattern) { + continue; + } + } + + let is_bad = filename.starts_with("bad") || filename.starts_with("unsupported"); + if (config.mode == Mode::Good && is_bad) || (config.mode == Mode::Bad && !is_bad) { + continue; + } + + let mut data = Vec::new(); + File::open(&path)?.read_to_end(&mut data)?; + let decoded = if !is_bad && config.phase == Phase::Write { + Some(decode_good(&data)) + } else { + None + }; + cases.push(Case { + name: filename, + data, + is_bad, + decoded, + }); + } + + cases.sort_by(|left, right| left.name.cmp(&right.name)); + Ok(cases) +} + +fn run_cases(cases: &[Case], phase: Phase) -> u64 { + let mut digest = 0u64; + for case in cases { + digest = digest.rotate_left(7) ^ run_case(case, phase); + } + digest +} + +fn run_case(case: &Case, phase: Phase) -> u64 { + if case.is_bad { + run_bad(&case.data) + } else { + run_good(case, phase) + } +} + +fn decode_good(data: &[u8]) -> Vec { + let mut ret = Vec::new(); + read::XzDecoder::new_multi_decoder(data) + .read_to_end(&mut ret) + .unwrap(); + ret +} + +fn run_good(case: &Case, phase: Phase) -> u64 { + match phase { + Phase::Both => run_good_both(&case.data), + Phase::Read => { + let ret = decode_good(&case.data); + fold_bytes(ret.len(), &ret) + } + Phase::Write => run_good_write(&case.data, case.decoded.as_deref().unwrap()), + } +} + +fn run_good_both(data: &[u8]) -> u64 { + let ret = decode_good(data); + run_good_write(data, &ret) +} + +fn run_good_write(data: &[u8], decoded_seed: &[u8]) -> u64 { + let ret = decoded_seed.to_vec(); + let mut w = write::XzDecoder::new_multi_decoder(ret); + w.write_all(data).unwrap(); + let ret = w.finish().unwrap(); + fold_bytes(data.len() + ret.len(), &ret) +} + +fn run_bad(data: &[u8]) -> u64 { + let mut ret = Vec::new(); + let stream = stream::Stream::new_stream_decoder(u64::MAX, stream::CONCATENATED).unwrap(); + let result = read::XzDecoder::new_stream(data, stream).read_to_end(&mut ret); + assert!(result.is_err(), "{result:?}"); + let mut w = write::XzDecoder::new(ret); + assert!(w.write_all(data).is_err() || w.finish().is_err()); + fold_bytes(data.len(), data) +} + +fn measure(bytes_per_iter: usize, iters: usize, warmup: usize, mut work: F) -> Measurement +where + F: FnMut() -> u64, +{ + let mut digest = 0u64; + for _ in 0..warmup { + digest ^= black_box(work()); + } + + let start = Instant::now(); + for _ in 0..iters { + digest ^= black_box(work()); + } + let elapsed = start.elapsed(); + let mib = (bytes_per_iter as f64 * iters as f64) / (1024.0 * 1024.0); + + Measurement { + elapsed, + throughput_mib_s: mib / elapsed.as_secs_f64(), + digest, + } +} + +fn print_measurement(measurement: &Measurement, iters: usize) { + println!( + "{}: total={:.3?} ns_per_iter={:.0} throughput_mib_s={:.2} digest={:#x}", + BACKEND_NAME, + measurement.elapsed, + measurement.elapsed.as_nanos() as f64 / iters as f64, + measurement.throughput_mib_s, + measurement.digest + ); +} + +fn fold_bytes(len: usize, data: &[u8]) -> u64 { + let mut acc = len as u64; + for &byte in data.iter().take(32) { + acc = acc.rotate_left(5) ^ u64::from(byte); + } + acc +} diff --git a/liblzma-rs/src/common/easy_buffer_encoder.rs b/liblzma-rs/src/common/easy_buffer_encoder.rs deleted file mode 100644 index 74863c48..00000000 --- a/liblzma-rs/src/common/easy_buffer_encoder.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::common::stream_buffer_encoder::lzma_stream_buffer_encode; -use crate::types::*; -pub unsafe fn lzma_easy_buffer_encode( - preset: u32, - check: lzma_check, - allocator: *const lzma_allocator, - in_0: *const u8, - in_size: size_t, - out: *mut u8, - out_pos: *mut size_t, - out_size: size_t, -) -> lzma_ret { - let mut opt_easy: lzma_options_easy = lzma_options_easy { - filters: [lzma_filter { - id: 0, - options: core::ptr::null_mut(), - }; 5], - opt_lzma: lzma_options_lzma { - dict_size: 0, - preset_dict: core::ptr::null(), - preset_dict_size: 0, - lc: 0, - lp: 0, - pb: 0, - mode: 0, - nice_len: 0, - mf: 0, - depth: 0, - ext_flags: 0, - ext_size_low: 0, - ext_size_high: 0, - reserved_int4: 0, - reserved_int5: 0, - reserved_int6: 0, - reserved_int7: 0, - reserved_int8: 0, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_ptr1: core::ptr::null_mut(), - reserved_ptr2: core::ptr::null_mut(), - }, - }; - if lzma_easy_preset(::core::ptr::addr_of_mut!(opt_easy), preset) { - return LZMA_OPTIONS_ERROR; - } - lzma_stream_buffer_encode( - ::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter, - check, - allocator, - in_0, - in_size, - out, - out_pos, - out_size, - ) -} diff --git a/liblzma-rs/src/common/easy_decoder_memusage.rs b/liblzma-rs/src/common/easy_decoder_memusage.rs deleted file mode 100644 index 556efa9d..00000000 --- a/liblzma-rs/src/common/easy_decoder_memusage.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::types::*; -pub fn lzma_easy_decoder_memusage(preset: u32) -> u64 { - let mut opt_easy: lzma_options_easy = lzma_options_easy { - filters: [lzma_filter { - id: 0, - options: core::ptr::null_mut(), - }; 5], - opt_lzma: lzma_options_lzma { - dict_size: 0, - preset_dict: core::ptr::null(), - preset_dict_size: 0, - lc: 0, - lp: 0, - pb: 0, - mode: 0, - nice_len: 0, - mf: 0, - depth: 0, - ext_flags: 0, - ext_size_low: 0, - ext_size_high: 0, - reserved_int4: 0, - reserved_int5: 0, - reserved_int6: 0, - reserved_int7: 0, - reserved_int8: 0, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_ptr1: core::ptr::null_mut(), - reserved_ptr2: core::ptr::null_mut(), - }, - }; - if unsafe { lzma_easy_preset(::core::ptr::addr_of_mut!(opt_easy), preset) } { - return UINT32_MAX as u64; - } - unsafe { - lzma_raw_decoder_memusage(::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter) - } -} diff --git a/liblzma-rs/src/common/easy_encoder.rs b/liblzma-rs/src/common/easy_encoder.rs deleted file mode 100644 index 4ed491e4..00000000 --- a/liblzma-rs/src/common/easy_encoder.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::common::stream_encoder::lzma_stream_encoder; -use crate::types::*; -pub unsafe fn lzma_easy_encoder( - strm: *mut lzma_stream, - preset: u32, - check: lzma_check, -) -> lzma_ret { - let mut opt_easy: lzma_options_easy = lzma_options_easy { - filters: [lzma_filter { - id: 0, - options: core::ptr::null_mut(), - }; 5], - opt_lzma: lzma_options_lzma { - dict_size: 0, - preset_dict: core::ptr::null(), - preset_dict_size: 0, - lc: 0, - lp: 0, - pb: 0, - mode: 0, - nice_len: 0, - mf: 0, - depth: 0, - ext_flags: 0, - ext_size_low: 0, - ext_size_high: 0, - reserved_int4: 0, - reserved_int5: 0, - reserved_int6: 0, - reserved_int7: 0, - reserved_int8: 0, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_ptr1: core::ptr::null_mut(), - reserved_ptr2: core::ptr::null_mut(), - }, - }; - if lzma_easy_preset(::core::ptr::addr_of_mut!(opt_easy), preset) { - return LZMA_OPTIONS_ERROR; - } - lzma_stream_encoder( - strm, - ::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter, - check, - ) -} diff --git a/liblzma-rs/src/common/easy_encoder_memusage.rs b/liblzma-rs/src/common/easy_encoder_memusage.rs deleted file mode 100644 index 029acdf3..00000000 --- a/liblzma-rs/src/common/easy_encoder_memusage.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::types::*; -pub fn lzma_easy_encoder_memusage(preset: u32) -> u64 { - let mut opt_easy: lzma_options_easy = lzma_options_easy { - filters: [lzma_filter { - id: 0, - options: core::ptr::null_mut(), - }; 5], - opt_lzma: lzma_options_lzma { - dict_size: 0, - preset_dict: core::ptr::null(), - preset_dict_size: 0, - lc: 0, - lp: 0, - pb: 0, - mode: 0, - nice_len: 0, - mf: 0, - depth: 0, - ext_flags: 0, - ext_size_low: 0, - ext_size_high: 0, - reserved_int4: 0, - reserved_int5: 0, - reserved_int6: 0, - reserved_int7: 0, - reserved_int8: 0, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_ptr1: core::ptr::null_mut(), - reserved_ptr2: core::ptr::null_mut(), - }, - }; - if unsafe { lzma_easy_preset(::core::ptr::addr_of_mut!(opt_easy), preset) } { - return UINT32_MAX as u64; - } - unsafe { - lzma_raw_encoder_memusage(::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter) - } -} diff --git a/liblzma-rs/src/simple/arm.rs b/liblzma-rs/src/simple/arm.rs deleted file mode 100644 index bb184fdc..00000000 --- a/liblzma-rs/src/simple/arm.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::types::*; -unsafe extern "C" fn arm_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - size &= !(3); - let mut i: size_t = 0; - i = 0; - while i < size { - if *buffer.offset((i + 3) as isize) == 0xeb { - let mut src: u32 = (*buffer.offset((i + 2) as isize) as u32) << 16 - | (*buffer.offset((i + 1) as isize) as u32) << 8 - | *buffer.offset(i as isize) as u32; - src <<= 2; - let mut dest: u32 = 0; - if is_encoder { - dest = now_pos - .wrapping_add(i as u32) - .wrapping_add(8) - .wrapping_add(src); - } else { - dest = src.wrapping_sub(now_pos.wrapping_add(i as u32).wrapping_add(8)); - } - dest >>= 2; - *buffer.offset((i + 2) as isize) = (dest >> 16) as u8; - *buffer.offset((i + 1) as isize) = (dest >> 8) as u8; - *buffer.offset(i as isize) = dest as u8; - } - i += 4; - } - i -} -extern "C" fn arm_coder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, - is_encoder: bool, -) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - arm_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 4, - 4, - is_encoder, - ) - } -} -pub unsafe extern "C" fn lzma_simple_arm_encoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - arm_coder_init(next, allocator, filters, true) -} -pub unsafe extern "C" fn lzma_simple_arm_decoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - arm_coder_init(next, allocator, filters, false) -} diff --git a/liblzma-rs/src/simple/armthumb.rs b/liblzma-rs/src/simple/armthumb.rs deleted file mode 100644 index f17a4b0b..00000000 --- a/liblzma-rs/src/simple/armthumb.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::types::*; -unsafe extern "C" fn armthumb_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - if size < 4 { - return 0; - } - size -= 4; - let mut i: size_t = 0; - i = 0; - while i <= size { - if *buffer.offset((i + 1) as isize) & 0xf8 == 0xf0 - && *buffer.offset((i + 3) as isize) & 0xf8 == 0xf8 - { - let mut src: u32 = (*buffer.offset((i + 1) as isize) as u32 & 7) << 19 - | (*buffer.offset(i as isize) as u32) << 11 - | (*buffer.offset((i + 3) as isize) as u32 & 7) << 8 - | *buffer.offset((i + 2) as isize) as u32; - src <<= 1; - let mut dest: u32 = 0; - if is_encoder { - dest = now_pos - .wrapping_add(i as u32) - .wrapping_add(4) - .wrapping_add(src); - } else { - dest = src.wrapping_sub(now_pos.wrapping_add(i as u32).wrapping_add(4)); - } - dest >>= 1; - *buffer.offset((i + 1) as isize) = (0xf0 | dest >> 19 & 0x7) as u8; - *buffer.offset(i as isize) = (dest >> 11) as u8; - *buffer.offset((i + 3) as isize) = (0xf8 | dest >> 8 & 0x7) as u8; - *buffer.offset((i + 2) as isize) = dest as u8; - i += 2; - } - i += 2; - } - i -} -extern "C" fn armthumb_coder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, - is_encoder: bool, -) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - armthumb_code - as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 4, - 2, - is_encoder, - ) - } -} -pub unsafe extern "C" fn lzma_simple_armthumb_encoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - armthumb_coder_init(next, allocator, filters, true) -} -pub unsafe extern "C" fn lzma_simple_armthumb_decoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - armthumb_coder_init(next, allocator, filters, false) -} diff --git a/liblzma-rs/src/simple/powerpc.rs b/liblzma-rs/src/simple/powerpc.rs deleted file mode 100644 index 573672b1..00000000 --- a/liblzma-rs/src/simple/powerpc.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::types::*; -unsafe extern "C" fn powerpc_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - size &= !(3); - let mut i: size_t = 0; - i = 0; - while i < size { - if *buffer.offset(i as isize) >> 2 == 0x12 && *buffer.offset((i + 3) as isize) & 3 == 1 { - let src: u32 = (*buffer.offset(i as isize) as u32 & 3) << 24 - | (*buffer.offset((i + 1) as isize) as u32) << 16 - | (*buffer.offset((i + 2) as isize) as u32) << 8 - | *buffer.offset((i + 3) as isize) as u32 & !(3); - let mut dest: u32 = 0; - if is_encoder { - dest = now_pos.wrapping_add(i as u32).wrapping_add(src); - } else { - dest = src.wrapping_sub(now_pos.wrapping_add(i as u32)); - } - *buffer.offset(i as isize) = (0x48 | dest >> 24 & 0x3) as u8; - *buffer.offset((i + 1) as isize) = (dest >> 16) as u8; - *buffer.offset((i + 2) as isize) = (dest >> 8) as u8; - *buffer.offset((i + 3) as isize) &= 0x3; - *buffer.offset((i + 3) as isize) = - (*buffer.offset((i + 3) as isize) as u32 | dest) as u8; - } - i += 4; - } - i -} -extern "C" fn powerpc_coder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, - is_encoder: bool, -) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - powerpc_code - as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 4, - 4, - is_encoder, - ) - } -} -pub unsafe extern "C" fn lzma_simple_powerpc_encoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - powerpc_coder_init(next, allocator, filters, true) -} -pub unsafe extern "C" fn lzma_simple_powerpc_decoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - powerpc_coder_init(next, allocator, filters, false) -} diff --git a/liblzma-rs/src/simple/sparc.rs b/liblzma-rs/src/simple/sparc.rs deleted file mode 100644 index 84be333a..00000000 --- a/liblzma-rs/src/simple/sparc.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::types::*; -unsafe extern "C" fn sparc_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - size &= !(3); - let mut i: size_t = 0; - i = 0; - while i < size { - if *buffer.offset(i as isize) == 0x40 && *buffer.offset((i + 1) as isize) & 0xc0 == 0 - || *buffer.offset(i as isize) == 0x7f && *buffer.offset((i + 1) as isize) & 0xc0 == 0xc0 - { - let mut src: u32 = (*buffer.offset(i as isize) as u32) << 24 - | (*buffer.offset((i + 1) as isize) as u32) << 16 - | (*buffer.offset((i + 2) as isize) as u32) << 8 - | *buffer.offset((i + 3) as isize) as u32; - src <<= 2; - let mut dest: u32 = 0; - if is_encoder { - dest = now_pos.wrapping_add(i as u32).wrapping_add(src); - } else { - dest = src.wrapping_sub(now_pos.wrapping_add(i as u32)); - } - dest >>= 2; - dest = - 0u32.wrapping_sub(dest >> 22 & 1) << 22 & 0x3fffffff | dest & 0x3fffff | 0x40000000; - *buffer.offset(i as isize) = (dest >> 24) as u8; - *buffer.offset((i + 1) as isize) = (dest >> 16) as u8; - *buffer.offset((i + 2) as isize) = (dest >> 8) as u8; - *buffer.offset((i + 3) as isize) = dest as u8; - } - i += 4; - } - i -} -extern "C" fn sparc_coder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, - is_encoder: bool, -) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - sparc_code - as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 4, - 4, - is_encoder, - ) - } -} -pub unsafe extern "C" fn lzma_simple_sparc_encoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - sparc_coder_init(next, allocator, filters, true) -} -pub unsafe extern "C" fn lzma_simple_sparc_decoder_init( - next: *mut lzma_next_coder, - allocator: *const lzma_allocator, - filters: *const lzma_filter_info, -) -> lzma_ret { - sparc_coder_init(next, allocator, filters, false) -} diff --git a/perf-probe/Cargo.toml b/perf-probe/Cargo.toml new file mode 100644 index 00000000..9cde3646 --- /dev/null +++ b/perf-probe/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "perf-probe" +version = "0.1.0" +edition = "2021" +publish = false + +[features] +default = [] +xz = ["dep:xz"] +xz-sys = ["dep:xz-sys"] +liblzma-sys = ["dep:liblzma-sys"] + +[dependencies] +liblzma-sys = { path = "../liblzma-sys", optional = true } +xz = { path = "../xz", optional = true } +xz-sys = { path = "../xz-sys", optional = true } diff --git a/perf-probe/src/main.rs b/perf-probe/src/main.rs new file mode 100644 index 00000000..37cd579e --- /dev/null +++ b/perf-probe/src/main.rs @@ -0,0 +1,573 @@ +#![cfg(not(target_family = "wasm"))] + +#[cfg(any( + all(feature = "xz", feature = "xz-sys"), + all(feature = "xz", feature = "liblzma-sys"), + all(feature = "xz-sys", feature = "liblzma-sys"), +))] +compile_error!("Enable exactly one backend feature: xz, xz-sys, or liblzma-sys"); +#[cfg(not(any(feature = "xz", feature = "xz-sys", feature = "liblzma-sys")))] +compile_error!("Enable one backend feature: xz, xz-sys, or liblzma-sys"); + +use std::env; +use std::fs; +use std::hint::black_box; +use std::path::PathBuf; +use std::ptr; +use std::time::{Duration, Instant}; + +#[cfg(feature = "liblzma-sys")] +use liblzma_sys::{ + lzma_crc32, lzma_crc64, lzma_easy_buffer_encode, lzma_index as BackendIndex, + lzma_index_buffer_decode, lzma_index_end, lzma_index_uncompressed_size, + lzma_stream_buffer_bound, lzma_stream_buffer_decode, lzma_stream_flags as BackendStreamFlags, + lzma_stream_footer_decode, LZMA_CHECK_CRC64, LZMA_OK, LZMA_STREAM_HEADER_SIZE, +}; +#[cfg(feature = "xz")] +use xz::check::{crc32_fast::lzma_crc32, crc64_fast::lzma_crc64}; +#[cfg(feature = "xz")] +use xz::common::{ + easy_buffer_encoder::lzma_easy_buffer_encode, + index::{lzma_index_end, lzma_index_uncompressed_size}, + index_decoder::lzma_index_buffer_decode, + stream_buffer_decoder::lzma_stream_buffer_decode, + stream_buffer_encoder::lzma_stream_buffer_bound, + stream_flags_decoder::lzma_stream_footer_decode, +}; +#[cfg(feature = "xz")] +use xz::types::{ + lzma_index as BackendIndex, lzma_stream_flags as BackendStreamFlags, LZMA_CHECK_CRC64, LZMA_OK, + LZMA_STREAM_HEADER_SIZE, +}; +#[cfg(feature = "xz-sys")] +use xz_sys::{ + lzma_crc32, lzma_crc64, lzma_easy_buffer_encode, lzma_index as BackendIndex, + lzma_index_buffer_decode, lzma_index_end, lzma_index_uncompressed_size, + lzma_stream_buffer_bound, lzma_stream_buffer_decode, lzma_stream_flags as BackendStreamFlags, + lzma_stream_footer_decode, LZMA_CHECK_CRC64, LZMA_OK, LZMA_STREAM_HEADER_SIZE, +}; + +#[cfg(feature = "xz")] +const BACKEND_NAME: &str = "xz"; +#[cfg(feature = "liblzma-sys")] +const BACKEND_NAME: &str = "liblzma-sys"; +#[cfg(feature = "xz-sys")] +const BACKEND_NAME: &str = "xz-sys"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Workload { + Encode, + Decode, + Size, + Crc32, + Crc64, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum InputKind { + Random, + Text, +} + +#[derive(Debug)] +struct Config { + workload: Workload, + input_kind: InputKind, + input_path: Option, + compressed_input_path: Option, + save_output_path: Option, + size: usize, + chunk_size: Option, + expected_size: Option, + preset: u32, + iters: usize, + warmup: usize, +} + +#[derive(Debug)] +struct Measurement { + elapsed: Duration, + throughput_mib_s: f64, + digest: u64, +} + +fn main() { + let config = Config::parse(env::args().skip(1)).unwrap_or_else(|message| { + eprintln!("{message}"); + std::process::exit(2); + }); + + println!( + "config: backend={} workload={:?} input={:?} size={} preset={} iters={} warmup={}", + BACKEND_NAME, + config.workload, + config.input_kind, + config.size, + config.preset, + config.iters, + config.warmup + ); + if let Some(path) = &config.input_path { + println!("input_path: {}", path.display()); + } + if let Some(path) = &config.compressed_input_path { + println!("compressed_input_path: {}", path.display()); + } + if let Some(path) = &config.save_output_path { + println!("save_output_path: {}", path.display()); + } + + match config.workload { + Workload::Encode => run_encode(&config), + Workload::Decode => run_decode(&config), + Workload::Size => run_size(&config), + Workload::Crc32 => run_crc32(&config), + Workload::Crc64 => run_crc64(&config), + } +} + +impl Config { + fn parse(mut args: I) -> Result + where + I: Iterator, + { + let mut config = Self { + workload: Workload::Encode, + input_kind: InputKind::Text, + input_path: None, + compressed_input_path: None, + save_output_path: None, + size: 1024 * 1024, + chunk_size: None, + expected_size: None, + preset: 6, + iters: 200, + warmup: 20, + }; + + while let Some(arg) = args.next() { + match arg.as_str() { + "--workload" => { + config.workload = parse_workload(next_arg(&mut args, "--workload")?)?; + } + "--input-kind" => { + config.input_kind = parse_input_kind(next_arg(&mut args, "--input-kind")?)?; + } + "--input" => { + config.input_path = Some(PathBuf::from(next_arg(&mut args, "--input")?)); + } + "--compressed-input" => { + config.compressed_input_path = + Some(PathBuf::from(next_arg(&mut args, "--compressed-input")?)); + } + "--save-output" => { + config.save_output_path = + Some(PathBuf::from(next_arg(&mut args, "--save-output")?)); + } + "--size" => { + config.size = parse_usize(next_arg(&mut args, "--size")?, "--size")?; + } + "--chunk-size" => { + config.chunk_size = Some(parse_usize( + next_arg(&mut args, "--chunk-size")?, + "--chunk-size", + )?); + } + "--expected-size" => { + config.expected_size = Some(parse_usize( + next_arg(&mut args, "--expected-size")?, + "--expected-size", + )?); + } + "--preset" => { + config.preset = parse_u32(next_arg(&mut args, "--preset")?, "--preset")?; + } + "--iters" => { + config.iters = parse_usize(next_arg(&mut args, "--iters")?, "--iters")?; + } + "--warmup" => { + config.warmup = parse_usize(next_arg(&mut args, "--warmup")?, "--warmup")?; + } + "--help" | "-h" => return Err(usage()), + unknown => return Err(format!("unknown argument `{unknown}`\n\n{}", usage())), + } + } + + if config.iters == 0 { + return Err("`--iters` must be greater than zero".to_owned()); + } + + if matches!(config.chunk_size, Some(0)) { + return Err("`--chunk-size` must be greater than zero".to_owned()); + } + + if matches!(config.workload, Workload::Decode | Workload::Size) + && config.compressed_input_path.is_some() + && config.expected_size.is_none() + { + return Err( + "`decode`/`size` with `--compressed-input` also requires `--expected-size`" + .to_owned(), + ); + } + + if config.chunk_size.is_some() + && !matches!(config.workload, Workload::Crc32 | Workload::Crc64) + { + return Err("`--chunk-size` is only supported with crc32/crc64 workloads".to_owned()); + } + + Ok(config) + } +} + +fn usage() -> String { + let mut message = String::new(); + message.push_str("Usage:\n"); + message.push_str( + " cargo run -p perf-probe --release --no-default-features --features -- \\\n", + ); + message.push_str(" --workload [options]\n\n"); + message.push_str("Options:\n"); + message.push_str(" --input Read raw workload bytes from a file\n"); + message.push_str(" --compressed-input Read compressed bytes for decode\n"); + message.push_str(" --save-output Save encode/decode output bytes\n"); + message.push_str(" --input-kind \n"); + message + .push_str(" --size Synthetic input size when --input is omitted\n"); + message.push_str( + " --chunk-size Split crc32/crc64 input into incremental chunks\n", + ); + message.push_str( + " --expected-size Required for decode when --compressed-input is used\n", + ); + message.push_str(" --preset <0-9> LZMA preset used by encode/decode prep\n"); + message.push_str(" --iters Timed iterations\n"); + message.push_str(" --warmup Untimed warmup iterations\n"); + message +} + +fn next_arg(args: &mut I, flag: &str) -> Result +where + I: Iterator, +{ + args.next() + .ok_or_else(|| format!("missing value for `{flag}`\n\n{}", usage())) +} + +fn parse_workload(value: String) -> Result { + match value.as_str() { + "encode" => Ok(Workload::Encode), + "decode" => Ok(Workload::Decode), + "size" => Ok(Workload::Size), + "crc32" => Ok(Workload::Crc32), + "crc64" => Ok(Workload::Crc64), + _ => Err(format!("unsupported workload `{value}`")), + } +} + +fn parse_input_kind(value: String) -> Result { + match value.as_str() { + "random" => Ok(InputKind::Random), + "text" => Ok(InputKind::Text), + _ => Err(format!("unsupported input kind `{value}`")), + } +} + +fn parse_usize(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as usize: `{value}`")) +} + +fn parse_u32(value: String, flag: &str) -> Result { + value + .parse() + .map_err(|_| format!("failed to parse `{flag}` as u32: `{value}`")) +} + +fn load_raw_input(config: &Config) -> Result, std::io::Error> { + match &config.input_path { + Some(path) => fs::read(path), + None => Ok(match config.input_kind { + InputKind::Random => make_random_payload(config.size), + InputKind::Text => make_text_payload(config.size), + }), + } +} + +fn load_compressed_input(config: &Config) -> Result<(Vec, usize), std::io::Error> { + match &config.compressed_input_path { + Some(path) => Ok(( + fs::read(path)?, + config + .expected_size + .expect("expected_size checked during argument parsing"), + )), + None => { + let raw = load_raw_input(config)?; + let compressed = unsafe { backend_encode(&raw, config.preset) }; + Ok((compressed, raw.len())) + } + } +} + +fn make_random_payload(size: usize) -> Vec { + let mut x: u64 = 0x9E3779B97F4A7C15; + let mut out = Vec::with_capacity(size); + for _ in 0..size { + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + out.push((x.wrapping_mul(0x2545F4914F6CDD1D) >> 56) as u8); + } + out +} + +fn make_text_payload(size: usize) -> Vec { + let chunk = b"Portable Network Archive keeps long-tail formats maintainable by replacing risky C dependency paths with inspectable Rust implementations. "; + let mut out = Vec::with_capacity(size); + while out.len() < size { + let remaining = size - out.len(); + out.extend_from_slice(&chunk[..remaining.min(chunk.len())]); + } + out +} + +fn run_encode(config: &Config) { + let input = load_raw_input(config).unwrap_or_else(|err| { + eprintln!("failed to load input: {err}"); + std::process::exit(1); + }); + + let first = unsafe { backend_encode(&input, config.preset) }; + if let Some(path) = &config.save_output_path { + fs::write(path, &first).unwrap_or_else(|err| { + eprintln!("failed to write encoded output: {err}"); + std::process::exit(1); + }); + } + + let measurement = measure(input.len(), config.iters, config.warmup, || unsafe { + let output = backend_encode(&input, config.preset); + fold_bytes(output.len(), &output) + }); + print_measurement(&measurement, config.iters); +} + +fn run_decode(config: &Config) { + let (compressed, expected_size) = load_compressed_input(config).unwrap_or_else(|err| { + eprintln!("failed to load compressed input: {err}"); + std::process::exit(1); + }); + + let first = unsafe { backend_decode(&compressed, expected_size) }; + if let Some(path) = &config.save_output_path { + fs::write(path, &first).unwrap_or_else(|err| { + eprintln!("failed to write decoded output: {err}"); + std::process::exit(1); + }); + } + println!( + "decode_input: compressed_size={} original_size={}", + compressed.len(), + expected_size + ); + + let measurement = measure(expected_size, config.iters, config.warmup, || unsafe { + let output = backend_decode(&compressed, expected_size); + fold_bytes(output.len(), &output) + }); + print_measurement(&measurement, config.iters); +} + +fn run_size(config: &Config) { + let (compressed, expected_size) = load_compressed_input(config).unwrap_or_else(|err| { + eprintln!("failed to load compressed input: {err}"); + std::process::exit(1); + }); + println!( + "size_input: compressed_size={} original_size={}", + compressed.len(), + expected_size + ); + + let first = unsafe { backend_uncompressed_size(&compressed) }; + assert_eq!( + first, expected_size as u64, + "{BACKEND_NAME} size failed: expected {} got {}", + expected_size, first + ); + + let measurement = measure(compressed.len(), config.iters, config.warmup, || unsafe { + backend_uncompressed_size(&compressed) + }); + print_measurement(&measurement, config.iters); +} + +fn run_crc32(config: &Config) { + let input = load_raw_input(config).unwrap_or_else(|err| { + eprintln!("failed to load input: {err}"); + std::process::exit(1); + }); + let measurement = measure(input.len(), config.iters, config.warmup, || { + let slice = black_box(input.as_slice()); + let mut crc = 0u32; + if let Some(chunk_size) = config.chunk_size { + for chunk in slice.chunks(chunk_size) { + crc = unsafe { lzma_crc32(chunk.as_ptr(), chunk.len(), crc) }; + } + } else { + crc = unsafe { lzma_crc32(slice.as_ptr(), slice.len(), crc) }; + } + crc as u64 + }); + print_measurement(&measurement, config.iters); +} + +fn run_crc64(config: &Config) { + let input = load_raw_input(config).unwrap_or_else(|err| { + eprintln!("failed to load input: {err}"); + std::process::exit(1); + }); + let measurement = measure(input.len(), config.iters, config.warmup, || { + let slice = black_box(input.as_slice()); + let mut crc = 0u64; + if let Some(chunk_size) = config.chunk_size { + for chunk in slice.chunks(chunk_size) { + crc = unsafe { lzma_crc64(chunk.as_ptr(), chunk.len(), crc) }; + } + } else { + crc = unsafe { lzma_crc64(slice.as_ptr(), slice.len(), crc) }; + } + crc + }); + print_measurement(&measurement, config.iters); +} + +fn measure(bytes_per_iter: usize, iters: usize, warmup: usize, mut work: F) -> Measurement +where + F: FnMut() -> u64, +{ + let mut digest = 0u64; + for _ in 0..warmup { + digest ^= black_box(work()); + } + + let start = Instant::now(); + for _ in 0..iters { + digest ^= black_box(work()); + } + let elapsed = start.elapsed(); + let mib = (bytes_per_iter as f64 * iters as f64) / (1024.0 * 1024.0); + + Measurement { + elapsed, + throughput_mib_s: mib / elapsed.as_secs_f64(), + digest, + } +} + +fn print_measurement(measurement: &Measurement, iters: usize) { + println!( + "{}: total={:.3?} ns_per_iter={:.0} throughput_mib_s={:.2} digest={:#x}", + BACKEND_NAME, + measurement.elapsed, + measurement.elapsed.as_nanos() as f64 / iters as f64, + measurement.throughput_mib_s, + measurement.digest + ); +} + +fn fold_bytes(len: usize, data: &[u8]) -> u64 { + let mut acc = len as u64; + for &byte in data.iter().take(32) { + acc = acc.rotate_left(5) ^ u64::from(byte); + } + acc +} + +unsafe fn backend_encode(input: &[u8], preset: u32) -> Vec { + let bound = lzma_stream_buffer_bound(input.len()); + let mut out = vec![0u8; bound]; + let mut out_pos: usize = 0; + let ret = unsafe { + lzma_easy_buffer_encode( + preset, + LZMA_CHECK_CRC64, + ptr::null(), + input.as_ptr(), + input.len(), + out.as_mut_ptr(), + &mut out_pos, + out.len(), + ) + }; + assert_eq!(ret, LZMA_OK, "{BACKEND_NAME} encode failed with {ret}"); + out.truncate(out_pos); + out +} + +unsafe fn backend_decode(compressed: &[u8], out_size: usize) -> Vec { + let mut out = vec![0u8; out_size]; + let mut memlimit = u64::MAX; + let mut in_pos = 0usize; + let mut out_pos = 0usize; + let ret = unsafe { + lzma_stream_buffer_decode( + &mut memlimit, + 0, + ptr::null(), + compressed.as_ptr(), + &mut in_pos, + compressed.len(), + out.as_mut_ptr(), + &mut out_pos, + out.len(), + ) + }; + assert_eq!(ret, LZMA_OK, "{BACKEND_NAME} decode failed with {ret}"); + out.truncate(out_pos); + out +} + +unsafe fn backend_uncompressed_size(compressed: &[u8]) -> u64 { + let footer_len = LZMA_STREAM_HEADER_SIZE as usize; + let footer_offset = compressed + .len() + .checked_sub(footer_len) + .expect("compressed payload must contain at least a footer"); + let footer = compressed[footer_offset..].as_ptr(); + + let mut footer_flags = std::mem::MaybeUninit::::uninit(); + let footer_ret = unsafe { lzma_stream_footer_decode(footer_flags.as_mut_ptr(), footer) }; + assert_eq!( + footer_ret, LZMA_OK, + "{BACKEND_NAME} stream_footer_decode failed with {footer_ret}" + ); + let footer_flags = unsafe { footer_flags.assume_init() }; + + let index_plus_footer = footer_len + footer_flags.backward_size as usize; + let mut index_pos = 0usize; + let mut memlimit = u64::MAX; + let mut index = std::mem::MaybeUninit::<*mut BackendIndex>::uninit(); + let index_bytes = &compressed[compressed.len() - index_plus_footer..]; + let index_ret = unsafe { + lzma_index_buffer_decode( + index.as_mut_ptr(), + &mut memlimit, + ptr::null(), + index_bytes.as_ptr(), + &mut index_pos, + index_bytes.len(), + ) + }; + assert_eq!( + index_ret, LZMA_OK, + "{BACKEND_NAME} index_buffer_decode failed with {index_ret}" + ); + let index = unsafe { index.assume_init() }; + let size = unsafe { lzma_index_uncompressed_size(index) }; + unsafe { lzma_index_end(index, ptr::null()) }; + size +} diff --git a/scripts/compare_api_workloads.sh b/scripts/compare_api_workloads.sh new file mode 100755 index 00000000..014f70ce --- /dev/null +++ b/scripts/compare_api_workloads.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 1 ]]; then + cat <<'EOF' >&2 +Usage: scripts/compare_api_workloads.sh [example args...] + +Examples: + scripts/compare_api_workloads.sh standard-files --mode all --iters 200 --warmup 20 + scripts/compare_api_workloads.sh standard-files --mode good --iters 400 --warmup 40 + scripts/compare_api_workloads.sh standard-files --mode good --name-pattern delta --iters 400 --warmup 40 + scripts/compare_api_workloads.sh qc --mode both --cases 128 --max-size 4096 --iters 200 --warmup 20 + scripts/compare_api_workloads.sh bufread-trailing --mode both --input-size 1024 --trailing-size 123 --iters 1000 --warmup 100 +EOF + exit 2 +fi + +WORKLOAD="$1" +shift + +if [[ "$WORKLOAD" != "standard-files" && "$WORKLOAD" != "qc" && "$WORKLOAD" != "bufread-trailing" ]]; then + echo "unsupported API workload: $WORKLOAD" >&2 + exit 2 +fi + +command -v hyperfine >/dev/null 2>&1 || { + echo "hyperfine is required for compare_api_workloads.sh" >&2 + exit 1 +} + +RESULTS_DIR="target/perf-results" +mkdir -p "$RESULTS_DIR" + +RAW_ARGS=("$@") +RUST_TARGET="target/api-probe-rust" +C_TARGET="target/api-probe-c" + +case "$WORKLOAD" in + standard-files) + EXAMPLE_NAME="standard_files_probe" + ;; + qc) + EXAMPLE_NAME="qc_probe" + ;; + bufread-trailing) + EXAMPLE_NAME="bufread_trailing_probe" + ;; +esac + +RUST_BIN="$RUST_TARGET/release/examples/$EXAMPLE_NAME" +C_BIN="$C_TARGET/release/examples/$EXAMPLE_NAME" + +env CARGO_TARGET_DIR="$RUST_TARGET" cargo build --example "$EXAMPLE_NAME" --release >/dev/null +env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$C_TARGET" cargo build --example "$EXAMPLE_NAME" --release --no-default-features --features liblzma-sys >/dev/null + +hyperfine \ + --shell=none \ + --warmup 2 \ + --export-json "$RESULTS_DIR/api-${WORKLOAD}.json" \ + --export-markdown "$RESULTS_DIR/api-${WORKLOAD}.md" \ + --command-name xz \ + "$RUST_BIN ${RAW_ARGS[*]}" \ + --command-name c \ + "$C_BIN ${RAW_ARGS[*]}" + +cat < Number of measured runs per command (default: 5) + --warmup Warmup runs per command (default: 1) + --root-repeats Repeat the root test-binary bundle inside each timed command + --results-dir Where to write hyperfine reports + --skip-systest Only compare the root crate test suite +EOF + exit 0 + ;; + *) + echo "unknown argument: $1" >&2 + exit 2 + ;; + esac +done + +command -v hyperfine >/dev/null 2>&1 || { + echo "hyperfine is required for compare_backends.sh" >&2 + exit 1 +} + +mkdir -p "$RESULTS_DIR" + +ROOT_RUST_TARGET="target/perf-root-rust" +ROOT_C_TARGET="target/perf-root-c" +SYSTEST_RUST_TARGET="target/perf-systest-rust" +SYSTEST_C_TARGET="target/perf-systest-c" + +ROOT_RUST_CMD="./scripts/run_root_test_bins.sh $ROOT_RUST_TARGET $ROOT_REPEATS" +ROOT_C_CMD="./scripts/run_root_test_bins.sh $ROOT_C_TARGET $ROOT_REPEATS" +SYSTEST_RUST_CMD="env CARGO_TARGET_DIR=$SYSTEST_RUST_TARGET cargo test -p systest --release --no-default-features --features xz-sys -- --test-threads=1" +SYSTEST_C_CMD="env LZMA_API_STATIC=1 CARGO_TARGET_DIR=$SYSTEST_C_TARGET cargo test -p systest --release --no-default-features --features liblzma-sys -- --test-threads=1" + +echo "prebuilding root test binaries..." +env CARGO_TARGET_DIR="$ROOT_RUST_TARGET" cargo test --release --no-run >/dev/null +env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$ROOT_C_TARGET" cargo test --release --no-default-features --features liblzma-sys --no-run >/dev/null + +hyperfine \ + --shell=none \ + --runs "$RUNS" \ + --warmup "$WARMUP" \ + --export-json "$RESULTS_DIR/root-tests.json" \ + --export-markdown "$RESULTS_DIR/root-tests.md" \ + --command-name xz-tests \ + "$ROOT_RUST_CMD" \ + --command-name c-tests \ + "$ROOT_C_CMD" + +if [[ "$INCLUDE_SYSTEST" -eq 1 ]]; then + echo "prebuilding systest binaries..." + env CARGO_TARGET_DIR="$SYSTEST_RUST_TARGET" cargo test -p systest --release --no-default-features --features xz-sys --no-run >/dev/null + env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$SYSTEST_C_TARGET" cargo test -p systest --release --no-default-features --features liblzma-sys --no-run >/dev/null + + hyperfine \ + --shell=none \ + --runs "$RUNS" \ + --warmup "$WARMUP" \ + --export-json "$RESULTS_DIR/systest.json" \ + --export-markdown "$RESULTS_DIR/systest.md" \ + --command-name xz-sys-systest \ + "$SYSTEST_RUST_CMD" \ + --command-name c-systest \ + "$SYSTEST_C_CMD" +fi + +cat <&2 +Usage: scripts/compare_workloads.sh [perf-probe args...] + +Examples: + scripts/compare_workloads.sh encode --input-kind random --size 1048576 --iters 20 --warmup 3 + scripts/compare_workloads.sh decode --input-kind random --size 1048576 --iters 50 --warmup 5 + scripts/compare_workloads.sh size --input-kind random --size 1048576 --iters 400 --warmup 40 +EOF + exit 2 +fi + +WORKLOAD="$1" +shift + +command -v hyperfine >/dev/null 2>&1 || { + echo "hyperfine is required for compare_workloads.sh" >&2 + exit 1 +} + +RESULTS_DIR="target/perf-results" +mkdir -p "$RESULTS_DIR" + +RAW_ARGS=("$@") +RUST_TARGET="target/perf-probe-rust" +C_TARGET="target/perf-probe-c" +RUST_BIN="$RUST_TARGET/release/perf-probe" +C_BIN="$C_TARGET/release/perf-probe" + +env CARGO_TARGET_DIR="$RUST_TARGET" cargo build -p perf-probe --release --no-default-features --features xz >/dev/null +env LZMA_API_STATIC=1 CARGO_TARGET_DIR="$C_TARGET" cargo build -p perf-probe --release --no-default-features --features liblzma-sys >/dev/null + +if [[ "$WORKLOAD" == "decode" ]]; then + SIZE="" + for ((i = 0; i < ${#RAW_ARGS[@]}; i++)); do + if [[ "${RAW_ARGS[$i]}" == "--size" ]]; then + SIZE="${RAW_ARGS[$((i + 1))]}" + break + fi + done + if [[ -z "$SIZE" ]]; then + echo "decode comparison currently requires --size so expected output size is known" >&2 + exit 2 + fi + + COMPRESSED_INPUT="$RESULTS_DIR/decode-input-${SIZE}.xz" + "$C_BIN" \ + --workload encode "${RAW_ARGS[@]}" --iters 1 --warmup 0 --save-output "$COMPRESSED_INPUT" >/dev/null + + RUST_CMD=( + "$RUST_BIN" + --workload decode + --compressed-input "$COMPRESSED_INPUT" + --expected-size "$SIZE" + ) + C_CMD=( + "$C_BIN" + --workload decode + --compressed-input "$COMPRESSED_INPUT" + --expected-size "$SIZE" + ) +else + RUST_CMD=( + "$RUST_BIN" + --workload "$WORKLOAD" "${RAW_ARGS[@]}" + ) + C_CMD=( + "$C_BIN" + --workload "$WORKLOAD" "${RAW_ARGS[@]}" + ) +fi + +hyperfine \ + --shell=none \ + --warmup 2 \ + --export-json "$RESULTS_DIR/${WORKLOAD}.json" \ + --export-markdown "$RESULTS_DIR/${WORKLOAD}.md" \ + --command-name xz \ + "${RUST_CMD[*]}" \ + --command-name c \ + "${C_CMD[*]}" + +cat < [options] + +Options: + --package Cargo package to inspect (default: xz) + --format Output format for cargo-asm (default: asm) + --features Cargo feature list passed to cargo-asm + --target-dir Cargo target dir (default: target/codegen) + +Example: + scripts/inspect_codegen.sh xz::lzma::lzma2_encoder::lzma2_encode \ + --package xz --format asm +EOF +} + +if [[ $# -gt 0 && ( "$1" == "--help" || "$1" == "-h" ) ]]; then + print_usage + exit 0 +fi + +if [[ $# -lt 1 ]]; then + print_usage + exit 2 +fi + +SYMBOL="$1" +shift + +PACKAGE="xz" +FORMAT="asm" +FEATURES="" +TARGET_DIR="target/codegen" + +while [[ $# -gt 0 ]]; do + case "$1" in + --package) + PACKAGE="$2" + shift 2 + ;; + --format) + FORMAT="$2" + shift 2 + ;; + --features) + FEATURES="$2" + shift 2 + ;; + --target-dir) + TARGET_DIR="$2" + shift 2 + ;; + --help|-h) + print_usage + exit 0 + ;; + *) + echo "unknown argument: $1" >&2 + exit 2 + ;; + esac +done + +command -v cargo-asm >/dev/null 2>&1 || { + echo "cargo-asm is required for inspect_codegen.sh" >&2 + exit 1 +} + +ARGS=( + --manifest-path Cargo.toml + --target-dir "$TARGET_DIR" + -p "$PACKAGE" + --lib + --release + --this-workspace + "--$FORMAT" + "$SYMBOL" +) + +if [[ -n "$FEATURES" ]]; then + ARGS+=(--features "$FEATURES") +fi + +cargo-asm "${ARGS[@]}" diff --git a/scripts/profile_backend.sh b/scripts/profile_backend.sh new file mode 100755 index 00000000..ee74f222 --- /dev/null +++ b/scripts/profile_backend.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 2 ]]; then + cat <<'EOF' >&2 +Usage: scripts/profile_backend.sh [backend_probe args...] + +Examples: + scripts/profile_backend.sh xz decode --size 1048576 --iters 500 --warmup 50 + scripts/profile_backend.sh both encode --input-kind random --size 8388608 + scripts/profile_backend.sh xz size --input-kind random --size 1048576 --iters 800 --warmup 80 + +Environment: + PROFILER=auto|samply|perf|plain default: auto + PROFILE_OUT= optional profiler output file +EOF + exit 2 +fi + +BACKEND="$1" +WORKLOAD="$2" +shift 2 + +PROFILER="${PROFILER:-auto}" +mkdir -p target/perf-results + +case "$BACKEND" in + c|liblzma-sys) + FEATURE="liblzma-sys" + TARGET_DIR="target/profile-bench-c" + BACKEND_ENV=(LZMA_API_STATIC=1) + ;; + xz|rust) + FEATURE="xz" + TARGET_DIR="target/profile-bench-rust" + BACKEND_ENV=() + ;; + xz-sys) + FEATURE="xz-sys" + TARGET_DIR="target/profile-bench-xz-sys" + BACKEND_ENV=() + ;; + both) + echo "profile_backend.sh profiles one backend at a time; use xz, xz-sys, or liblzma-sys" >&2 + exit 2 + ;; + *) + echo "unknown backend: $BACKEND" >&2 + exit 2 + ;; +esac + +COMMON_CMD=( + cargo run + -p perf-probe + --release + --no-default-features + --features "$FEATURE" + -- + --workload "$WORKLOAD" +) +COMMON_CMD+=("$@") + +case "$PROFILER" in + auto) + if command -v samply >/dev/null 2>&1; then + PROFILER="samply" + elif command -v perf >/dev/null 2>&1; then + PROFILER="perf" + else + PROFILER="plain" + fi + ;; +esac + +if [[ "$PROFILER" == "samply" ]]; then + OUT="${PROFILE_OUT:-target/perf-results/${BACKEND}-${WORKLOAD}.json}" + env "${BACKEND_ENV[@]}" CARGO_TARGET_DIR="$TARGET_DIR" CARGO_PROFILE_RELEASE_DEBUG=1 \ + samply record --save-only -o "$OUT" -- "${COMMON_CMD[@]}" + echo "profile written to $OUT" +elif [[ "$PROFILER" == "perf" ]]; then + OUT="${PROFILE_OUT:-target/perf-results/${BACKEND}-${WORKLOAD}.perf.data}" + env "${BACKEND_ENV[@]}" CARGO_TARGET_DIR="$TARGET_DIR" CARGO_PROFILE_RELEASE_DEBUG=1 \ + perf record -g --output "$OUT" -- "${COMMON_CMD[@]}" + echo "profile written to $OUT" +elif [[ "$PROFILER" == "plain" ]]; then + env "${BACKEND_ENV[@]}" CARGO_TARGET_DIR="$TARGET_DIR" CARGO_PROFILE_RELEASE_DEBUG=1 "${COMMON_CMD[@]}" +else + echo "unsupported PROFILER=$PROFILER" >&2 + exit 2 +fi diff --git a/scripts/run_root_test_bins.sh b/scripts/run_root_test_bins.sh new file mode 100755 index 00000000..b831b195 --- /dev/null +++ b/scripts/run_root_test_bins.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 1 || $# -gt 2 ]]; then + cat <<'EOF' >&2 +Usage: scripts/run_root_test_bins.sh [repeats] + +Run the prebuilt root crate unit and integration test binaries directly, +without going through `cargo test`. This avoids cargo/doctest overhead when +comparing backend runtime performance. +EOF + exit 2 +fi + +TARGET_DIR="$1" +REPEATS="${2:-1}" +DEPS_DIR="$TARGET_DIR/release/deps" + +if [[ "$REPEATS" -lt 1 ]]; then + echo "repeats must be >= 1" >&2 + exit 2 +fi + +for ((repeat = 0; repeat < REPEATS; repeat++)); do + for prefix in \ + "liblzma-" \ + "drop_incomplete-" \ + "sys_equivalence-" \ + "xz-" + do + BIN="" + while IFS= read -r candidate; do + if [[ -x "$candidate" ]]; then + BIN="$candidate" + break + fi + done < <(find "$DEPS_DIR" -maxdepth 1 -type f -name "${prefix}*" | sort) + if [[ -z "$BIN" ]]; then + echo "missing test binary for prefix $prefix in $DEPS_DIR" >&2 + exit 1 + fi + ARGS=(--test-threads=1) + if [[ "$prefix" == "liblzma-" ]]; then + # QuickCheck-based tests use a fresh RNG per process, so backend-to-backend + # wall-clock comparisons on them are not stable. Cover those paths with + # deterministic focused probes instead. + ARGS+=( + --skip read::tests::qc + --skip read::tests::qc_lzma1 + --skip write::tests::qc + --skip write::tests::qc_lzma1 + --skip tests::all + --skip tests::copy + --skip tests::size + ) + fi + "$BIN" "${ARGS[@]}" + done +done diff --git a/src/bufread.rs b/src/bufread.rs index 342caa24..9cb27d96 100644 --- a/src/bufread.rs +++ b/src/bufread.rs @@ -6,6 +6,7 @@ use std::io::prelude::*; #[cfg(feature = "parallel")] use crate::stream::MtStreamBuilder; use crate::stream::{Action, Check, Status, Stream}; +use crate::sys as liblzma_sys; /// A xz encoder, or compressor. /// diff --git a/src/lib.rs b/src/lib.rs index 994a4845..a2ef1626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,14 +52,58 @@ #![doc(html_root_url = "https://docs.rs/liblzma/0.4.6")] #![deny(missing_docs)] -#[cfg(not(any(feature = "rust-backend", feature = "c-backend")))] -compile_error!("Either `rust-backend` or `c-backend` feature must be enabled"); +#[cfg(any( + all(feature = "xz", feature = "xz-sys"), + all(feature = "xz", feature = "liblzma-sys"), + all(feature = "xz-sys", feature = "liblzma-sys"), +))] +compile_error!("Enable exactly one of `xz`, `xz-sys`, or `liblzma-sys`"); + +#[cfg(not(any(feature = "xz", feature = "xz-sys", feature = "liblzma-sys")))] +compile_error!("Enable `xz`, `xz-sys`, or `liblzma-sys`"); + +#[cfg(feature = "xz")] +pub(crate) mod sys { + pub(crate) use xz::check::check::lzma_check_is_supported; + pub(crate) use xz::common::{ + alone_decoder::lzma_alone_decoder, + alone_encoder::lzma_alone_encoder, + auto_decoder::lzma_auto_decoder, + common::{lzma_code, lzma_end, lzma_memlimit_get, lzma_memlimit_set}, + easy_encoder::lzma_easy_encoder, + filter_decoder::{lzma_properties_decode, lzma_raw_decoder}, + filter_encoder::lzma_raw_encoder, + index::{lzma_index_end, lzma_index_uncompressed_size}, + index_decoder::lzma_index_buffer_decode, + lzip_decoder::lzma_lzip_decoder, + stream_decoder::lzma_stream_decoder, + stream_encoder::lzma_stream_encoder, + stream_flags_decoder::lzma_stream_footer_decode, + string_conversion::LZMA_PRESET_DEFAULT, + }; + #[cfg(feature = "parallel")] + pub(crate) use xz::common::{ + filter_encoder::lzma_mt_block_size, + stream_mt::{ + lzma_stream_decoder_mt, lzma_stream_encoder_mt, lzma_stream_encoder_mt_memusage, + }, + }; + pub(crate) use xz::lz::lz_encoder::lzma_mf_is_supported; + pub(crate) use xz::lzma::lzma_encoder_presets::{lzma_lzma_preset, LZMA_PRESET_LEVEL_MASK}; + pub(crate) use xz::types::*; +} -// When c-backend is active (without rust-backend), alias liblzma_c_sys -// so that internal `liblzma_sys::` references resolve to the C library. -#[cfg(all(feature = "c-backend", not(feature = "rust-backend")))] -extern crate liblzma_c_sys as liblzma_sys; +#[cfg(feature = "xz-sys")] +pub(crate) mod sys { + pub(crate) use xz_sys::*; +} + +#[cfg(feature = "liblzma-sys")] +pub(crate) mod sys { + pub(crate) use liblzma_sys::*; +} +use crate::sys as liblzma_sys; use std::io::{self, prelude::*}; pub mod stream; @@ -111,7 +155,6 @@ pub fn copy_decode(source: R, mut destination: W) -> io::Resu } /// Find the size in bytes of uncompressed data from xz file. -#[cfg(any(feature = "rust-backend", feature = "bindgen"))] pub fn uncompressed_size(mut source: R) -> io::Result { use std::mem::MaybeUninit; let mut footer = [0u8; liblzma_sys::LZMA_STREAM_HEADER_SIZE as usize]; @@ -179,13 +222,13 @@ pub fn uncompressed_size(mut source: R) -> io::Result { Ok(uncompressed_size) } -#[cfg(all(test, not(target_family = "wasm")))] +#[cfg(test)] mod tests { use super::*; - #[cfg(not(target_family = "wasm"))] use quickcheck::quickcheck; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + use wasm_bindgen_test::wasm_bindgen_test as test; - #[cfg(not(target_family = "wasm"))] #[test] fn all() { quickcheck(test as fn(_) -> _); @@ -197,7 +240,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[test] fn copy() { quickcheck(test as fn(_) -> _); @@ -211,9 +253,7 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[test] - #[cfg(any(feature = "rust-backend", feature = "bindgen"))] fn size() { quickcheck(test as fn(_) -> _); diff --git a/src/read.rs b/src/read.rs index d550db0d..cea37de8 100644 --- a/src/read.rs +++ b/src/read.rs @@ -226,10 +226,7 @@ impl Write for XzDecoder { #[cfg(test)] mod tests { use super::*; - #[cfg(not(target_family = "wasm"))] - use crate::stream::LzmaOptions; - use crate::stream::PRESET_EXTREME; - #[cfg(not(target_family = "wasm"))] + use crate::stream::{LzmaOptions, PRESET_EXTREME}; use quickcheck::quickcheck; use rand::{thread_rng, Rng}; use std::iter; @@ -329,7 +326,6 @@ mod tests { assert_eq!(data, m); } - #[cfg(not(target_family = "wasm"))] #[test] fn qc_lzma1() { quickcheck(test as fn(_) -> _); @@ -345,7 +341,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[test] fn qc() { quickcheck(test as fn(_) -> _); @@ -359,7 +354,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[cfg(feature = "parallel")] #[test] fn qc_parallel_encode() { @@ -385,7 +379,6 @@ mod tests { assert_eq!(data, m); } - #[cfg(not(target_family = "wasm"))] #[cfg(feature = "parallel")] #[test] fn qc_parallel_decode() { diff --git a/src/stream.rs b/src/stream.rs index 1ae9551e..4cbc7ec4 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -4,12 +4,16 @@ //! encoding/decoding of LZMA streams. Each [`Stream`] is either an encoder or //! decoder and processes data in a streaming fashion. +#![cfg_attr(feature = "xz", allow(unused_unsafe))] + use std::collections::LinkedList; use std::error; use std::fmt; use std::io; use std::mem; +use crate::sys as liblzma_sys; + /// Representation of an in-memory LZMA encoding or decoding stream. /// /// Wraps the raw underlying `lzma_stream` type and provides the ability to @@ -665,6 +669,7 @@ impl Check { #[inline] pub fn is_supported(&self) -> bool { let ret = unsafe { liblzma_sys::lzma_check_is_supported(*self as liblzma_sys::lzma_check) }; + ret != 0 } } @@ -675,6 +680,7 @@ impl MatchFinder { pub fn is_supported(&self) -> bool { let ret = unsafe { liblzma_sys::lzma_mf_is_supported(*self as liblzma_sys::lzma_match_finder) }; + ret != 0 } } diff --git a/src/write.rs b/src/write.rs index ae24fab5..02d7ef82 100644 --- a/src/write.rs +++ b/src/write.rs @@ -8,6 +8,7 @@ use std::io::prelude::*; #[cfg(feature = "parallel")] use crate::stream::MtStreamBuilder; use crate::stream::{Action, Check, Status, Stream}; +use crate::sys as liblzma_sys; pub use auto_finish::{AutoFinishXzDecoder, AutoFinishXzEncoder}; /// A compression stream which will have uncompressed data written to it and @@ -382,10 +383,7 @@ impl Drop for XzDecoder { #[cfg(test)] mod tests { use super::*; - #[cfg(not(target_family = "wasm"))] - use crate::stream::LzmaOptions; - use crate::stream::PRESET_EXTREME; - #[cfg(not(target_family = "wasm"))] + use crate::stream::{LzmaOptions, PRESET_EXTREME}; use quickcheck::quickcheck; use std::iter::repeat; #[cfg(all(target_family = "wasm", target_os = "unknown"))] @@ -423,7 +421,6 @@ mod tests { assert_eq!(data, input); } - #[cfg(not(target_family = "wasm"))] #[test] fn qc_lzma1() { quickcheck(test as fn(_) -> _); @@ -439,7 +436,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[test] fn qc() { quickcheck(test as fn(_) -> _); @@ -452,7 +448,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[cfg(feature = "parallel")] #[test] fn qc_parallel_encode() { @@ -466,7 +461,6 @@ mod tests { } } - #[cfg(not(target_family = "wasm"))] #[cfg(feature = "parallel")] #[test] fn qc_parallel_decode() { diff --git a/systest/Cargo.toml b/systest/Cargo.toml index 6c2b8724..fd393d7b 100644 --- a/systest/Cargo.toml +++ b/systest/Cargo.toml @@ -7,15 +7,14 @@ edition = "2021" publish = false [dependencies] -liblzma-c-sys = { package = "liblzma-sys", path = "../liblzma-sys", optional = true } -liblzma-rs-sys = { path = "../liblzma-rs-sys", optional = true } +liblzma-sys = { path = "../liblzma-sys", optional = true } +xz-sys = { path = "../xz-sys", optional = true } libc = "0.2" [build-dependencies] -ctest2 = "0.4" +ctest = "0.5" [features] -default = ["c-sys"] -c-sys = ["liblzma-c-sys"] -rs-sys = ["liblzma-rs-sys"] -bindgen = ["c-sys", "liblzma-c-sys/bindgen"] +liblzma-sys = ["dep:liblzma-sys"] +xz-sys = ["dep:xz-sys"] +bindgen = ["liblzma-sys", "liblzma-sys/bindgen"] diff --git a/systest/build.rs b/systest/build.rs index 736a65d4..5e28d86a 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -1,17 +1,107 @@ use std::env; +use std::fs; +use std::path::{Path, PathBuf}; + +fn target_deps_dir() -> PathBuf { + let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + let workspace_root = manifest_dir.parent().unwrap(); + let target_root = env::var_os("CARGO_TARGET_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| workspace_root.join("target")); + let profile = env::var("PROFILE").unwrap(); + let target = env::var("TARGET").unwrap(); + + let triple_root = target_root.join(&target); + let profile_root = if triple_root.exists() { + triple_root.join(&profile) + } else { + target_root.join(&profile) + }; + profile_root.join("deps") +} + +fn latest_rlib(deps_dir: &Path, crate_name: &str) -> PathBuf { + let prefix = format!("lib{crate_name}-"); + fs::read_dir(deps_dir) + .unwrap() + .filter_map(|entry| { + let entry = entry.ok()?; + let path = entry.path(); + let file_name = path.file_name()?.to_str()?; + (file_name.starts_with(&prefix) && path.extension().is_some_and(|ext| ext == "rlib")) + .then_some(path) + }) + .max_by_key(|path| fs::metadata(path).and_then(|m| m.modified()).ok()) + .unwrap_or_else(|| { + panic!( + "missing compiled dependency for {crate_name} in {}", + deps_dir.display() + ) + }) +} + +fn write_rustc_wrapper( + out_dir: &Path, + deps_dir: &Path, + bare_externs: &[&str], + path_externs: &[(&str, PathBuf)], +) -> PathBuf { + let real_rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string()); + let wrapper = if cfg!(windows) { + out_dir.join("ctest-rustc.bat") + } else { + out_dir.join("ctest-rustc.sh") + }; + + let mut args = format!("-L dependency=\"{}\"", deps_dir.display()); + for name in bare_externs { + args.push_str(&format!(" --extern {name}")); + } + for (name, path) in path_externs { + args.push_str(&format!(" --extern {name}=\"{}\"", path.display())); + } + + let script = if cfg!(windows) { + format!("@echo off\r\n\"{real_rustc}\" {args} %*\r\n") + } else { + format!("#!/bin/sh\nexec \"{real_rustc}\" {args} \"$@\"\n") + }; + + fs::write(&wrapper, script).unwrap(); + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(&wrapper).unwrap().permissions(); + perms.set_mode(0o755); + fs::set_permissions(&wrapper, perms).unwrap(); + } + + wrapper +} fn main() { - let use_c_sys = env::var_os("CARGO_FEATURE_C_SYS").is_some(); - let use_rs_sys = env::var_os("CARGO_FEATURE_RS_SYS").is_some(); + let use_c_sys = env::var_os("CARGO_FEATURE_LIBLZMA_SYS").is_some(); + let use_rs_sys = env::var_os("CARGO_FEATURE_XZ_SYS").is_some(); + let use_parallel = env::var_os("CARGO_FEATURE_PARALLEL").is_some(); match (use_c_sys, use_rs_sys) { (true, false) | (false, true) => {} - _ => panic!("Enable exactly one of features: c-sys or rs-sys"), + _ => panic!("Enable exactly one of features: liblzma-sys or xz-sys"), } - let mut cfg = ctest2::TestGenerator::new(); + let mut cfg = ctest::TestGenerator::new(); + let use_bindgen = env::var_os("CARGO_FEATURE_BINDGEN").is_some(); + if use_bindgen { + cfg.cfg("feature", Some("bindgen")); + } if use_c_sys { if let Ok(out) = env::var("DEP_LZMA_INCLUDE") { cfg.include(&out); + } else { + // pkg-config-backed liblzma-sys builds can return early without exporting + // cargo:include metadata. Fall back to the vendored upstream API headers so + // systest can still compile its generated probe. + cfg.include("../liblzma-sys/xz/src/liblzma/api"); } } else { // Reuse vendored upstream headers to verify C header compatibility. @@ -19,14 +109,80 @@ fn main() { } cfg.header("lzma.h"); - cfg.type_name(|n, _s, _| n.to_string()); + cfg.rename_struct_ty(|ty| Some(ty.to_string())); + cfg.rename_union_ty(|ty| Some(ty.to_string())); + cfg.rename_struct_field(|s, field| { + if s.ident() == "lzma_options_delta" && field.ident() == "type_" { + Some("type".to_string()) + } else { + None + } + }); cfg.define("LZMA_API_STATIC", None); - cfg.skip_type(|n| n == "__enum_ty"); + cfg.skip_struct(move |s| { + use_bindgen && (s.ident().ends_with("_s") || s.ident().contains("__bindgen_ty_")) + }); + cfg.skip_union(move |u| use_bindgen && u.ident().contains("__bindgen_ty_")); + cfg.skip_struct_field(move |s, field| { + use_bindgen + && s.ident() == "lzma_index_iter" + && matches!(field.ident(), "stream" | "block" | "internal") + }); + cfg.skip_struct_field_type(move |s, field| { + use_bindgen + && s.ident() == "lzma_index_iter" + && matches!(field.ident(), "stream" | "block" | "internal") + }); + cfg.skip_fn(move |f| { + use_bindgen + && !use_parallel + && matches!( + f.ident(), + "lzma_stream_decoder_mt" + | "lzma_stream_encoder_mt" + | "lzma_stream_encoder_mt_memusage" + ) + }); + cfg.skip_alias(move |n| { + matches!(n.ident(), "__enum_ty" | "c_enum" | "lzma_reserved_enum") + || (use_bindgen + && matches!( + n.ident(), + "lzma_internal" | "lzma_index" | "lzma_index_hash" + )) + }); + cfg.skip_signededness(move |ty| { + use_bindgen && matches!(ty, "lzma_delta_type" | "lzma_index_iter_mode") + }); + if use_bindgen { + cfg.skip_const(|c| { + c.ident().starts_with("lzma_") + || matches!( + c.ident(), + "LZMA_H_INTERNAL" | "LZMA_VERSION_COMMIT" | "LZMA_VERSION_STABILITY_STRING" + ) + }); + } let rust_api = if use_c_sys { "../liblzma-sys/src/lib.rs" } else { - "../liblzma-rs-sys/src/lib.rs" + "../xz-sys/src/lib.rs" }; - cfg.generate(rust_api, "all.rs"); + + let deps_dir = target_deps_dir(); + let bare_externs = vec!["libc"]; + let mut path_externs = Vec::new(); + if use_rs_sys { + path_externs.push(("xz", latest_rlib(&deps_dir, "xz"))); + } + let rustc_wrapper = write_rustc_wrapper( + &PathBuf::from(env::var_os("OUT_DIR").unwrap()), + &deps_dir, + &bare_externs, + &path_externs, + ); + env::set_var("RUSTC", &rustc_wrapper); + + ctest::generate_test(&mut cfg, rust_api, "all.rs").unwrap(); } diff --git a/systest/src/main.rs b/systest/src/main.rs index 81b91f5d..74629307 100644 --- a/systest/src/main.rs +++ b/systest/src/main.rs @@ -1,13 +1,13 @@ #![allow(bad_style)] -#[cfg(all(feature = "c-sys", feature = "rs-sys"))] -compile_error!("Enable exactly one backend feature: c-sys or rs-sys"); -#[cfg(not(any(feature = "c-sys", feature = "rs-sys")))] -compile_error!("Enable one backend feature: c-sys or rs-sys"); +#[cfg(all(feature = "liblzma-sys", feature = "xz-sys"))] +compile_error!("Enable exactly one backend feature: liblzma-sys or xz-sys"); +#[cfg(not(any(feature = "liblzma-sys", feature = "xz-sys")))] +compile_error!("Enable one backend feature: liblzma-sys or xz-sys"); -#[cfg(feature = "c-sys")] -use liblzma_c_sys::*; -#[cfg(feature = "rs-sys")] -use liblzma_rs_sys::*; +#[cfg(feature = "liblzma-sys")] +use liblzma_sys::*; +#[cfg(feature = "xz-sys")] +use xz_sys::*; include!(concat!(env!("OUT_DIR"), "/all.rs")); diff --git a/tests/sys_equivalence.rs b/tests/sys_equivalence.rs index 9c92e038..be3ae82f 100644 --- a/tests/sys_equivalence.rs +++ b/tests/sys_equivalence.rs @@ -1,17 +1,11 @@ -#![cfg(all( - not(target_family = "wasm"), - feature = "rust-backend", - feature = "c-backend" -))] +#![cfg(not(target_family = "wasm"))] use std::collections::BTreeMap; use std::fs; +use std::mem; use std::path::Path; use std::ptr; -use liblzma_c_sys as c_sys; -use liblzma_sys as rs_sys; - fn parse_feature_table(cargo_toml: &str) -> BTreeMap> { let mut in_features = false; let mut features = BTreeMap::new(); @@ -65,7 +59,7 @@ fn parse_feature_table(cargo_toml: &str) -> BTreeMap> { #[test] fn rs_sys_avoids_literal_lzma_const_defs() { - let src = include_str!("../liblzma-rs-sys/src/lib.rs"); + let src = include_str!("../xz-sys/src/lib.rs"); let mut stmt = String::new(); let mut start_line = 0usize; let mut in_const = false; @@ -83,8 +77,8 @@ fn rs_sys_avoids_literal_lzma_const_defs() { stmt.push(' '); if trimmed.ends_with(';') { assert!( - stmt.contains("= liblzma_rs::"), - "LZMA const must alias liblzma_rs symbol, not use local literal (line {}): {}", + stmt.contains("= xz::"), + "LZMA const must alias xz symbol, not use local literal (line {}): {}", start_line, stmt ); @@ -96,10 +90,10 @@ fn rs_sys_avoids_literal_lzma_const_defs() { #[test] fn rs_sys_uses_libc_size_t() { - let src = include_str!("../liblzma-rs-sys/src/lib.rs"); + let src = include_str!("../xz-sys/src/lib.rs"); assert!( src.contains("use libc::size_t;"), - "liblzma-rs-sys must import libc::size_t directly" + "xz-sys must import libc::size_t directly" ); assert!( !src.contains("type size_t ="), @@ -107,14 +101,75 @@ fn rs_sys_uses_libc_size_t() { ); } +#[test] +fn rs_sys_exports_required_public_wrappers() { + let src = include_str!("../xz-sys/src/lib.rs"); + + for name in [ + "lzma_alloc", + "lzma_alloc_zero", + "lzma_free", + "lzma_bcj_arm64_encode", + "lzma_bcj_arm64_decode", + "lzma_bcj_riscv_encode", + "lzma_bcj_riscv_decode", + "lzma_bcj_x86_encode", + "lzma_bcj_x86_decode", + ] { + assert!( + src.contains(&format!("fn {name}(")), + "xz-sys must export wrapper for {name}", + ); + } +} + +#[test] +fn rs_sys_exports_all_c_backend_functions() { + let c_bindgen = include_str!("../liblzma-sys/src/bindgen.rs"); + let c_manual = include_str!("../liblzma-sys/src/manual.rs"); + let rs_sys = include_str!("../xz-sys/src/lib.rs"); + + let c_api: std::collections::BTreeSet<_> = c_bindgen + .lines() + .chain(c_manual.lines()) + .filter_map(|line| line.trim().strip_prefix("pub fn ")) + .filter_map(|line| line.split_once('(').map(|(name, _)| name.trim())) + .filter(|name| name.starts_with("lzma_")) + .collect(); + + let rs_api: std::collections::BTreeSet<_> = rs_sys + .lines() + .filter_map(|line| { + let line = line.trim(); + line.strip_prefix("pub unsafe extern \"C\" fn ") + .or_else(|| line.strip_prefix("pub extern \"C\" fn ")) + }) + .filter_map(|line| line.split_once('(').map(|(name, _)| name.trim())) + .filter(|name| name.starts_with("lzma_")) + .collect(); + + let missing: Vec<_> = c_api.difference(&rs_api).copied().collect(); + assert!( + missing.is_empty(), + "xz-sys is missing public functions from liblzma-sys: {missing:?}", + ); + + let extras: Vec<_> = rs_api.difference(&c_api).copied().collect(); + assert_eq!( + extras, + vec!["lzma_alloc", "lzma_alloc_zero", "lzma_free"], + "unexpected extra public functions in xz-sys: {extras:?}", + ); +} + #[test] fn cargo_features_match_c_backend() { let c_sys_features = parse_feature_table(include_str!("../liblzma-sys/Cargo.toml")); - let rs_sys_features = parse_feature_table(include_str!("../liblzma-rs-sys/Cargo.toml")); + let rs_sys_features = parse_feature_table(include_str!("../xz-sys/Cargo.toml")); assert_eq!( rs_sys_features, c_sys_features, - "liblzma-rs-sys feature table must stay compatible with liblzma-sys", + "xz-sys feature table must stay compatible with liblzma-sys", ); } @@ -124,8 +179,8 @@ fn api_constants_match_c_backend() { ($($name:ident),+ $(,)?) => { $( assert_eq!( - rs_sys::$name as u128, - c_sys::$name as u128, + xz_sys::$name as u128, + liblzma_sys::$name as u128, "constant mismatch: {}", stringify!($name) ); @@ -134,6 +189,9 @@ fn api_constants_match_c_backend() { } assert_const_eq!( + LZMA_VERSION_MAJOR, + LZMA_VERSION_MINOR, + LZMA_VERSION_PATCH, LZMA_OK, LZMA_STREAM_END, LZMA_NO_CHECK, @@ -185,6 +243,11 @@ fn api_constants_match_c_backend() { LZMA_VLI_MAX, LZMA_VLI_UNKNOWN, LZMA_VLI_BYTES_MAX, + LZMA_CHECK_ID_MAX, + LZMA_CHECK_SIZE_MAX, + LZMA_FILTERS_MAX, + LZMA_DELTA_DIST_MIN, + LZMA_DELTA_DIST_MAX, LZMA_FILTER_X86, LZMA_FILTER_POWERPC, LZMA_FILTER_IA64, @@ -197,6 +260,14 @@ fn api_constants_match_c_backend() { LZMA_FILTER_LZMA1, LZMA_FILTER_LZMA2, LZMA_STREAM_HEADER_SIZE, + LZMA_BLOCK_HEADER_SIZE_MIN, + LZMA_BLOCK_HEADER_SIZE_MAX, + ); + + assert_eq!( + xz_sys::LZMA_DELTA_TYPE_BYTE as u128, + liblzma_sys::lzma_delta_type_LZMA_DELTA_TYPE_BYTE as u128, + "constant mismatch: LZMA_DELTA_TYPE_BYTE", ); } @@ -207,12 +278,15 @@ fn api_constant_types_match_c_backend() { macro_rules! assert_const_type_eq { ($($name:ident),+ $(,)?) => { $( - assert_same_type(c_sys::$name, rs_sys::$name); + assert_same_type(liblzma_sys::$name, xz_sys::$name); )+ }; } assert_const_type_eq!( + LZMA_VERSION_MAJOR, + LZMA_VERSION_MINOR, + LZMA_VERSION_PATCH, LZMA_OK, LZMA_STREAM_END, LZMA_NO_CHECK, @@ -264,6 +338,11 @@ fn api_constant_types_match_c_backend() { LZMA_VLI_MAX, LZMA_VLI_UNKNOWN, LZMA_VLI_BYTES_MAX, + LZMA_CHECK_ID_MAX, + LZMA_CHECK_SIZE_MAX, + LZMA_FILTERS_MAX, + LZMA_DELTA_DIST_MIN, + LZMA_DELTA_DIST_MAX, LZMA_FILTER_X86, LZMA_FILTER_POWERPC, LZMA_FILTER_IA64, @@ -276,6 +355,13 @@ fn api_constant_types_match_c_backend() { LZMA_FILTER_LZMA1, LZMA_FILTER_LZMA2, LZMA_STREAM_HEADER_SIZE, + LZMA_BLOCK_HEADER_SIZE_MIN, + LZMA_BLOCK_HEADER_SIZE_MAX, + ); + + assert_same_type( + liblzma_sys::lzma_delta_type_LZMA_DELTA_TYPE_BYTE, + xz_sys::LZMA_DELTA_TYPE_BYTE, ); } @@ -284,14 +370,14 @@ fn api_type_layout_matches_c_backend() { macro_rules! assert_layout_eq { ($name:ident) => { assert_eq!( - std::mem::size_of::(), - std::mem::size_of::(), + std::mem::size_of::(), + std::mem::size_of::(), "size mismatch: {}", stringify!($name) ); assert_eq!( - std::mem::align_of::(), - std::mem::align_of::(), + std::mem::align_of::(), + std::mem::align_of::(), "align mismatch: {}", stringify!($name) ); @@ -303,12 +389,14 @@ fn api_type_layout_matches_c_backend() { assert_layout_eq!(lzma_action); assert_layout_eq!(lzma_check); assert_layout_eq!(lzma_vli); + assert_layout_eq!(lzma_delta_type); assert_layout_eq!(lzma_mode); assert_layout_eq!(lzma_match_finder); assert_layout_eq!(lzma_allocator); assert_layout_eq!(lzma_stream); assert_layout_eq!(lzma_filter); assert_layout_eq!(lzma_options_lzma); + assert_layout_eq!(lzma_options_delta); assert_layout_eq!(lzma_stream_flags); assert_layout_eq!(lzma_options_bcj); @@ -316,10 +404,10 @@ fn api_type_layout_matches_c_backend() { assert_layout_eq!(lzma_mt); // Opaque types can have intentionally different concrete representations. - let _: *mut rs_sys::lzma_internal = std::ptr::null_mut(); - let _: *mut c_sys::lzma_internal = std::ptr::null_mut(); - let _: *mut rs_sys::lzma_index = std::ptr::null_mut(); - let _: *mut c_sys::lzma_index = std::ptr::null_mut(); + let _: *mut xz_sys::lzma_internal = std::ptr::null_mut(); + let _: *mut liblzma_sys::lzma_internal = std::ptr::null_mut(); + let _: *mut xz_sys::lzma_index = std::ptr::null_mut(); + let _: *mut liblzma_sys::lzma_index = std::ptr::null_mut(); } #[test] @@ -327,8 +415,8 @@ fn api_functions_are_exported() { macro_rules! assert_fn_exported { ($($name:ident),+ $(,)?) => { $( - let _ = c_sys::$name as *const () as usize; - let _ = rs_sys::$name as *const () as usize; + let _ = liblzma_sys::$name as *const () as usize; + let _ = xz_sys::$name as *const () as usize; )+ }; } @@ -399,102 +487,92 @@ fn api_functions_are_exported() { ); } +macro_rules! encode_easy_impl { + ($sys:ident, $input:expr) => {{ + let bound = $sys::lzma_stream_buffer_bound($input.len()); + let mut out = vec![0u8; bound]; + let mut out_pos: usize = 0; + let ret = $sys::lzma_easy_buffer_encode( + 6, + $sys::LZMA_CHECK_CRC64, + ptr::null(), + $input.as_ptr(), + $input.len(), + out.as_mut_ptr(), + &mut out_pos, + out.len(), + ); + out.truncate(out_pos); + (ret as u32, out) + }}; +} + +macro_rules! decode_stream_impl { + ($sys:ident, $input:expr, $expected_size_hint:expr) => {{ + let mut out = Vec::with_capacity($expected_size_hint.max(256)); + let mut stream: $sys::lzma_stream = unsafe { mem::zeroed() }; + let mut ret = $sys::lzma_stream_decoder(&mut stream, u64::MAX, 0); + if ret as u32 != $sys::LZMA_OK as u32 { + return (ret as u32, out); + } + + loop { + if out.spare_capacity_mut().is_empty() { + let additional = out.capacity().max(256); + out.reserve(additional); + } + + let spare = out.spare_capacity_mut(); + stream.next_in = $input.as_ptr(); + stream.avail_in = $input.len() - stream.total_in as usize; + stream.next_out = spare.as_ptr() as *mut u8; + stream.avail_out = spare.len(); + + ret = $sys::lzma_code(&mut stream, $sys::LZMA_FINISH); + + let written = spare.len() - stream.avail_out; + unsafe { + out.set_len(out.len() + written); + } + + if ret as u32 == $sys::LZMA_STREAM_END as u32 { + ret = $sys::LZMA_OK; + break; + } + + if ret as u32 != $sys::LZMA_OK as u32 { + break; + } + + if stream.avail_out != 0 { + ret = $sys::LZMA_BUF_ERROR; + break; + } + } + + $sys::lzma_end(&mut stream); + (ret as u32, out) + }}; +} + #[inline] unsafe fn c_encode_easy(input: &[u8]) -> (u32, Vec) { - let bound = c_sys::lzma_stream_buffer_bound(input.len()); - let mut out = vec![0u8; bound]; - let mut out_pos: usize = 0; - let ret = c_sys::lzma_easy_buffer_encode( - 6, - c_sys::LZMA_CHECK_CRC64, - ptr::null(), - input.as_ptr(), - input.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - out.truncate(out_pos); - (ret as u32, out) + encode_easy_impl!(liblzma_sys, input) } #[inline] unsafe fn rs_encode_easy(input: &[u8]) -> (u32, Vec) { - let bound = rs_sys::lzma_stream_buffer_bound(input.len()); - let mut out = vec![0u8; bound]; - let mut out_pos: usize = 0; - let ret = rs_sys::lzma_easy_buffer_encode( - 6, - rs_sys::LZMA_CHECK_CRC64, - ptr::null(), - input.as_ptr(), - input.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - out.truncate(out_pos); - (ret as u32, out) + encode_easy_impl!(xz_sys, input) } #[inline] unsafe fn c_decode_stream_buffer(input: &[u8], expected_size_hint: usize) -> (u32, Vec) { - let mut cap = expected_size_hint.max(input.len() * 6 + 128).max(256); - let max_cap = 64 * 1024 * 1024; - - loop { - let mut out = vec![0u8; cap]; - let mut memlimit = u64::MAX; - let mut in_pos = 0usize; - let mut out_pos = 0usize; - let ret = c_sys::lzma_stream_buffer_decode( - &mut memlimit, - 0, - ptr::null(), - input.as_ptr(), - &mut in_pos, - input.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - if ret as u32 == c_sys::LZMA_BUF_ERROR as u32 && cap < max_cap { - cap = (cap * 2).min(max_cap); - continue; - } - out.truncate(out_pos); - return (ret as u32, out); - } + decode_stream_impl!(liblzma_sys, input, expected_size_hint) } #[inline] unsafe fn rs_decode_stream_buffer(input: &[u8], expected_size_hint: usize) -> (u32, Vec) { - let mut cap = expected_size_hint.max(input.len() * 6 + 128).max(256); - let max_cap = 64 * 1024 * 1024; - - loop { - let mut out = vec![0u8; cap]; - let mut memlimit = u64::MAX; - let mut in_pos = 0usize; - let mut out_pos = 0usize; - let ret = rs_sys::lzma_stream_buffer_decode( - &mut memlimit, - 0, - ptr::null(), - input.as_ptr(), - &mut in_pos, - input.len(), - out.as_mut_ptr(), - &mut out_pos, - out.len(), - ); - if ret as u32 == rs_sys::LZMA_BUF_ERROR as u32 && cap < max_cap { - cap = (cap * 2).min(max_cap); - continue; - } - out.truncate(out_pos); - return (ret as u32, out); - } + decode_stream_impl!(xz_sys, input, expected_size_hint) } fn deterministic_payload(case: usize) -> Vec { @@ -531,7 +609,7 @@ fn differential_roundtrip_across_backends() { ); assert_eq!( c_enc_ret, - c_sys::LZMA_OK as u32, + liblzma_sys::LZMA_OK as u32, "C encoder failed at case {case} with ret {c_enc_ret}" ); diff --git a/liblzma-rs-sys/Cargo.toml b/xz-sys/Cargo.toml similarity index 90% rename from liblzma-rs-sys/Cargo.toml rename to xz-sys/Cargo.toml index c9b7be0c..2ec9c90a 100644 --- a/liblzma-rs-sys/Cargo.toml +++ b/xz-sys/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "liblzma-rs-sys" +name = "xz-sys" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" -description = "liblzma-sys compatible API layer backed by pure Rust liblzma-rs" +description = "liblzma-sys compatible API layer backed by pure Rust xz" [lib] crate-type = ["rlib", "staticlib"] @@ -22,5 +22,5 @@ parallel = [] wasm = ["static", "bindgen"] [dependencies] -liblzma-rs = { path = "../liblzma-rs" } +xz = { path = "../xz" } libc = "0.2" diff --git a/liblzma-rs-sys/src/lib.rs b/xz-sys/src/lib.rs similarity index 56% rename from liblzma-rs-sys/src/lib.rs rename to xz-sys/src/lib.rs index dc0e191a..393a2013 100644 --- a/liblzma-rs-sys/src/lib.rs +++ b/xz-sys/src/lib.rs @@ -1,6 +1,6 @@ -//! liblzma-sys compatible API layer backed by pure Rust liblzma-rs +//! liblzma-sys compatible API layer backed by pure Rust xz //! -//! Re-exports symbols from liblzma-rs with the same names and signatures +//! Re-exports symbols from xz with the same names and signatures //! as liblzma-sys, enabling drop-in replacement. //! //! Because c2rust generates per-file type definitions, this layer provides @@ -26,151 +26,218 @@ type wasm_size_t = usize; #[cfg(all(target_family = "wasm", target_os = "unknown"))] use self::wasm_size_t as size_t; -// === Canonical type aliases === -// On MSVC, C enums are c_int; elsewhere c_uint (matching liblzma-sys manual.rs) +/************************ + * Canonical type aliases + ************************/ + +/* + * Match liblzma-sys' platform-dependent C enum ABI directly. + */ #[cfg(target_env = "msvc")] -#[doc(hidden)] -pub type __enum_ty = c_int; +type c_enum = c_int; #[cfg(not(target_env = "msvc"))] -#[doc(hidden)] -pub type __enum_ty = c_uint; - -pub type lzma_ret = __enum_ty; -pub type lzma_action = __enum_ty; -pub type lzma_check = __enum_ty; -pub type lzma_mode = __enum_ty; -pub type lzma_match_finder = __enum_ty; +type c_enum = c_uint; + +pub type lzma_ret = c_enum; +pub type lzma_action = c_enum; +pub type lzma_check = c_enum; +pub type lzma_mode = c_enum; +pub type lzma_match_finder = c_enum; pub type lzma_bool = c_uchar; pub type lzma_vli = u64; - -// === Canonical struct re-exports === -pub use liblzma_rs::common::index_hash::lzma_index_hash; -pub use liblzma_rs::types::lzma_allocator; -pub use liblzma_rs::types::lzma_block; -pub use liblzma_rs::types::lzma_filter; -pub use liblzma_rs::types::lzma_index; -pub use liblzma_rs::types::lzma_index_iter; -pub use liblzma_rs::types::lzma_index_iter_mode; -pub use liblzma_rs::types::lzma_mt; -pub use liblzma_rs::types::lzma_options_lzma; -pub use liblzma_rs::types::lzma_stream; -pub use liblzma_rs::types::lzma_stream_flags; +pub type lzma_delta_type = c_uint; + +/**************************** + * Canonical struct re-exports + ****************************/ +pub use xz::common::index_hash::lzma_index_hash; +pub use xz::types::lzma_allocator; +pub use xz::types::lzma_block; +pub use xz::types::lzma_filter; +pub use xz::types::lzma_index; +pub use xz::types::lzma_index_iter; +pub use xz::types::lzma_index_iter_mode; +pub use xz::types::lzma_mt; +pub use xz::types::lzma_options_lzma; +pub use xz::types::lzma_stream; +pub use xz::types::lzma_stream_flags; #[repr(C)] pub struct lzma_options_bcj { pub start_offset: u32, } +#[repr(C)] +pub struct lzma_options_delta { + pub type_: lzma_delta_type, + pub dist: u32, + pub reserved_int1: u32, + pub reserved_int2: u32, + pub reserved_int3: u32, + pub reserved_int4: u32, + pub reserved_ptr1: *mut c_void, + pub reserved_ptr2: *mut c_void, +} + pub enum lzma_internal {} -// ========================================================================= -// Constants -// ========================================================================= +/****************** + * Basic Features * + ******************/ -// --- Return codes --- -pub use liblzma_rs::types::{ +/* `lzma/version.h`: compile-time version constants */ +pub const LZMA_VERSION_MAJOR: u32 = xz::common::common::LZMA_VERSION_MAJOR as u32; +pub const LZMA_VERSION_MINOR: u32 = xz::common::common::LZMA_VERSION_MINOR as u32; +pub const LZMA_VERSION_PATCH: u32 = xz::common::common::LZMA_VERSION_PATCH as u32; +pub const LZMA_VERSION: u32 = xz::common::common::LZMA_VERSION as u32; + +/* `lzma/base.h`: return codes */ +pub use xz::types::{ LZMA_BUF_ERROR, LZMA_DATA_ERROR, LZMA_FORMAT_ERROR, LZMA_GET_CHECK, LZMA_MEMLIMIT_ERROR, LZMA_MEM_ERROR, LZMA_NO_CHECK, LZMA_OK, LZMA_OPTIONS_ERROR, LZMA_PROG_ERROR, LZMA_SEEK_NEEDED, LZMA_STREAM_END, LZMA_UNSUPPORTED_CHECK, }; -// --- Actions --- -pub use liblzma_rs::types::{ - LZMA_FINISH, LZMA_FULL_BARRIER, LZMA_FULL_FLUSH, LZMA_RUN, LZMA_SYNC_FLUSH, -}; +/* `lzma/base.h`: actions */ +pub use xz::types::{LZMA_FINISH, LZMA_FULL_BARRIER, LZMA_FULL_FLUSH, LZMA_RUN, LZMA_SYNC_FLUSH}; -// --- Check types --- -pub use liblzma_rs::types::{ - LZMA_CHECK_CRC32, LZMA_CHECK_CRC64, LZMA_CHECK_NONE, LZMA_CHECK_SHA256, -}; +/* `lzma/vli.h`: backward size / VLI */ +pub const LZMA_BACKWARD_SIZE_MIN: lzma_vli = xz::types::LZMA_BACKWARD_SIZE_MIN as lzma_vli; +pub const LZMA_BACKWARD_SIZE_MAX: lzma_vli = xz::types::LZMA_BACKWARD_SIZE_MAX as lzma_vli; +pub use xz::types::{LZMA_VLI_MAX, LZMA_VLI_UNKNOWN}; +pub const LZMA_VLI_BYTES_MAX: usize = xz::types::LZMA_VLI_BYTES_MAX as usize; + +/* `lzma/check.h`: check types */ +pub use xz::types::{LZMA_CHECK_CRC32, LZMA_CHECK_CRC64, LZMA_CHECK_NONE, LZMA_CHECK_SHA256}; +pub const LZMA_CHECK_ID_MAX: u32 = xz::types::LZMA_CHECK_ID_MAX as u32; +pub const LZMA_CHECK_SIZE_MAX: u32 = xz::types::LZMA_CHECK_SIZE_MAX as u32; -// --- Modes / match finders --- -pub use liblzma_rs::types::{ +/*********** + * Filters * + ***********/ + +/* `lzma/lzma12.h`: modes / match finders */ +pub use xz::types::{ LZMA_MF_BT2, LZMA_MF_BT3, LZMA_MF_BT4, LZMA_MF_HC3, LZMA_MF_HC4, LZMA_MODE_FAST, LZMA_MODE_NORMAL, }; -// --- Filter IDs --- -pub use liblzma_rs::types::{ +/* `lzma/filter.h`: filter IDs */ +pub use xz::types::{ LZMA_FILTER_ARM, LZMA_FILTER_ARM64, LZMA_FILTER_ARMTHUMB, LZMA_FILTER_DELTA, LZMA_FILTER_IA64, LZMA_FILTER_LZMA1, LZMA_FILTER_LZMA2, LZMA_FILTER_POWERPC, LZMA_FILTER_RISCV, LZMA_FILTER_SPARC, LZMA_FILTER_X86, }; - -// --- Decoder flags --- -pub use liblzma_rs::types::{ +pub const LZMA_FILTERS_MAX: u32 = xz::types::LZMA_FILTERS_MAX as u32; +pub const LZMA_DELTA_DIST_MIN: u32 = xz::types::LZMA_DELTA_DIST_MIN as u32; +pub const LZMA_DELTA_DIST_MAX: u32 = xz::types::LZMA_DELTA_DIST_MAX as u32; +pub const LZMA_DELTA_TYPE_BYTE: lzma_delta_type = + xz::types::LZMA_DELTA_TYPE_BYTE as lzma_delta_type; + +/********************* + * Container Formats * + *********************/ + +/* `lzma/container.h`: decoder flags */ +pub use xz::types::{ LZMA_CONCATENATED, LZMA_IGNORE_CHECK, LZMA_TELL_ANY_CHECK, LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK, }; -// --- Presets / option limits --- -pub const LZMA_PRESET_DEFAULT: u32 = - liblzma_rs::common::string_conversion::LZMA_PRESET_DEFAULT as u32; +/* `lzma/container.h`: presets / option limits */ +pub const LZMA_PRESET_DEFAULT: u32 = xz::common::string_conversion::LZMA_PRESET_DEFAULT as u32; pub const LZMA_PRESET_LEVEL_MASK: u32 = - liblzma_rs::lzma::lzma_encoder_presets::LZMA_PRESET_LEVEL_MASK as u32; -pub const LZMA_PRESET_EXTREME: u32 = liblzma_rs::types::LZMA_PRESET_EXTREME as u32; -pub const LZMA_DICT_SIZE_MIN: u32 = liblzma_rs::types::LZMA_DICT_SIZE_MIN as u32; + xz::lzma::lzma_encoder_presets::LZMA_PRESET_LEVEL_MASK as u32; +pub const LZMA_PRESET_EXTREME: u32 = xz::types::LZMA_PRESET_EXTREME as u32; +pub const LZMA_DICT_SIZE_MIN: u32 = xz::types::LZMA_DICT_SIZE_MIN as u32; pub const LZMA_DICT_SIZE_DEFAULT: u32 = - liblzma_rs::common::string_conversion::LZMA_DICT_SIZE_DEFAULT as u32; -pub const LZMA_LCLP_MIN: u32 = liblzma_rs::common::string_conversion::LZMA_LCLP_MIN as u32; -pub const LZMA_LCLP_MAX: u32 = liblzma_rs::types::LZMA_LCLP_MAX as u32; -pub const LZMA_LC_DEFAULT: u32 = liblzma_rs::lzma::lzma_encoder_presets::LZMA_LC_DEFAULT as u32; -pub const LZMA_LP_DEFAULT: u32 = liblzma_rs::lzma::lzma_encoder_presets::LZMA_LP_DEFAULT as u32; -pub const LZMA_PB_MIN: u32 = liblzma_rs::common::string_conversion::LZMA_PB_MIN as u32; -pub const LZMA_PB_MAX: u32 = liblzma_rs::types::LZMA_PB_MAX as u32; -pub const LZMA_PB_DEFAULT: u32 = liblzma_rs::lzma::lzma_encoder_presets::LZMA_PB_DEFAULT as u32; - -// --- Backward size / VLI --- -pub const LZMA_BACKWARD_SIZE_MIN: lzma_vli = liblzma_rs::types::LZMA_BACKWARD_SIZE_MIN as lzma_vli; -pub const LZMA_BACKWARD_SIZE_MAX: lzma_vli = liblzma_rs::types::LZMA_BACKWARD_SIZE_MAX as lzma_vli; -pub use liblzma_rs::types::{LZMA_VLI_MAX, LZMA_VLI_UNKNOWN}; -pub const LZMA_VLI_BYTES_MAX: usize = liblzma_rs::types::LZMA_VLI_BYTES_MAX as usize; - -// --- Stream header size --- -pub const LZMA_STREAM_HEADER_SIZE: u32 = liblzma_rs::types::LZMA_STREAM_HEADER_SIZE as u32; - -// ========================================================================= -// Functions -// ========================================================================= -// -// Functions are exposed as thin C ABI wrappers from this crate. -// Wrappers cast to canonical Rust implementation types and forward the call. - -// --- Common stream API --- + xz::common::string_conversion::LZMA_DICT_SIZE_DEFAULT as u32; +pub const LZMA_LCLP_MIN: u32 = xz::common::string_conversion::LZMA_LCLP_MIN as u32; +pub const LZMA_LCLP_MAX: u32 = xz::types::LZMA_LCLP_MAX as u32; +pub const LZMA_LC_DEFAULT: u32 = xz::lzma::lzma_encoder_presets::LZMA_LC_DEFAULT as u32; +pub const LZMA_LP_DEFAULT: u32 = xz::lzma::lzma_encoder_presets::LZMA_LP_DEFAULT as u32; +pub const LZMA_PB_MIN: u32 = xz::common::string_conversion::LZMA_PB_MIN as u32; +pub const LZMA_PB_MAX: u32 = xz::types::LZMA_PB_MAX as u32; +pub const LZMA_PB_DEFAULT: u32 = xz::lzma::lzma_encoder_presets::LZMA_PB_DEFAULT as u32; + +/********************* + * Advanced Features * + *********************/ + +/* `lzma/stream_flags.h`: stream header size */ +pub const LZMA_STREAM_HEADER_SIZE: u32 = xz::types::LZMA_STREAM_HEADER_SIZE as u32; +pub const LZMA_BLOCK_HEADER_SIZE_MIN: u32 = + xz::common::block_util::LZMA_BLOCK_HEADER_SIZE_MIN as u32; +pub const LZMA_BLOCK_HEADER_SIZE_MAX: u32 = xz::types::LZMA_BLOCK_HEADER_SIZE_MAX as u32; + +/******************* + * Function Wrappers + *******************/ + +/* + * Wrappers follow `lzma.h`'s public subheader layout where practical. + * They cast to canonical Rust implementation types and forward the call. + */ + +/****************** + * Basic Features * + ******************/ + +/* `lzma/version.h` */ + +#[no_mangle] +pub unsafe extern "C" fn lzma_version_number() -> u32 { + xz::common::common::lzma_version_number() +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_version_string() -> *const c_char { + xz::common::common::lzma_version_string() +} + +/* `lzma/base.h`: common stream API */ #[no_mangle] pub unsafe extern "C" fn lzma_code(strm: *mut lzma_stream, action: lzma_action) -> lzma_ret { - liblzma_rs::common::common::lzma_code(strm.cast(), action) + xz::common::common::lzma_code(strm.cast(), action) } #[no_mangle] pub unsafe extern "C" fn lzma_end(strm: *mut lzma_stream) { - liblzma_rs::common::common::lzma_end(strm.cast()) + xz::common::common::lzma_end(strm.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_memlimit_get(strm: *const lzma_stream) -> u64 { - liblzma_rs::common::common::lzma_memlimit_get(strm.cast()) + xz::common::common::lzma_memlimit_get(strm.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_memlimit_set(strm: *mut lzma_stream, new_memlimit: u64) -> lzma_ret { - liblzma_rs::common::common::lzma_memlimit_set(strm.cast(), new_memlimit) + xz::common::common::lzma_memlimit_set(strm.cast(), new_memlimit) } -// --- Version --- +/* `lzma/base.h`: allocation helpers */ #[no_mangle] -pub unsafe extern "C" fn lzma_version_number() -> u32 { - liblzma_rs::common::common::lzma_version_number() +pub unsafe extern "C" fn lzma_alloc(size: size_t, allocator: *const lzma_allocator) -> *mut c_void { + xz::common::common::lzma_alloc(size, allocator) } #[no_mangle] -pub unsafe extern "C" fn lzma_version_string() -> *const c_char { - liblzma_rs::common::common::lzma_version_string() +pub unsafe extern "C" fn lzma_alloc_zero( + size: size_t, + allocator: *const lzma_allocator, +) -> *mut c_void { + xz::common::common::lzma_alloc_zero(size, allocator) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_free(ptr: *mut c_void, allocator: *const lzma_allocator) { + xz::common::common::lzma_free(ptr, allocator) } -// --- Progress / memusage --- +/* `lzma/base.h`: progress / memusage */ #[no_mangle] pub unsafe extern "C" fn lzma_get_progress( @@ -178,51 +245,84 @@ pub unsafe extern "C" fn lzma_get_progress( progress_in: *mut u64, progress_out: *mut u64, ) { - liblzma_rs::common::common::lzma_get_progress(strm.cast(), progress_in, progress_out) + xz::common::common::lzma_get_progress(strm.cast(), progress_in, progress_out) } #[no_mangle] pub unsafe extern "C" fn lzma_memusage(strm: *const lzma_stream) -> u64 { - liblzma_rs::common::common::lzma_memusage(strm.cast()) + xz::common::common::lzma_memusage(strm.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_get_check(strm: *const lzma_stream) -> lzma_check { - liblzma_rs::common::common::lzma_get_check(strm.cast()) + xz::common::common::lzma_get_check(strm.cast()) +} + +/* `lzma/vli.h` */ + +#[no_mangle] +pub unsafe extern "C" fn lzma_vli_encode( + vli: lzma_vli, + vli_pos: *mut size_t, + out: *mut u8, + out_pos: *mut size_t, + out_size: size_t, +) -> lzma_ret { + xz::common::vli_encoder::lzma_vli_encode(vli, vli_pos, out, out_pos, out_size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_vli_decode( + vli: *mut lzma_vli, + vli_pos: *mut size_t, + input: *const u8, + in_pos: *mut size_t, + in_size: size_t, +) -> lzma_ret { + xz::common::vli_decoder::lzma_vli_decode(vli, vli_pos, input, in_pos, in_size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_vli_size(vli: lzma_vli) -> u32 { + xz::common::vli_size::lzma_vli_size(vli) } -// --- Check --- +/* `lzma/check.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_check_is_supported(check: lzma_check) -> lzma_bool { - liblzma_rs::check::check::lzma_check_is_supported(check) + xz::check::check::lzma_check_is_supported(check) } #[no_mangle] pub unsafe extern "C" fn lzma_check_size(check: lzma_check) -> u32 { - liblzma_rs::check::check::lzma_check_size(check) + xz::check::check::lzma_check_size(check) } #[no_mangle] pub unsafe extern "C" fn lzma_crc32(buf: *const u8, size: size_t, crc: u32) -> u32 { - liblzma_rs::check::crc32_fast::lzma_crc32(buf, size, crc) + xz::check::crc32_fast::lzma_crc32(buf, size, crc) } #[no_mangle] pub unsafe extern "C" fn lzma_crc64(buf: *const u8, size: size_t, crc: u64) -> u64 { - liblzma_rs::check::crc64_fast::lzma_crc64(buf, size, crc) + xz::check::crc64_fast::lzma_crc64(buf, size, crc) } -// --- Easy encoder --- +/********************* + * Container Formats * + *********************/ + +/* `lzma/container.h`: easy encoder */ #[no_mangle] pub unsafe extern "C" fn lzma_easy_encoder_memusage(preset: u32) -> u64 { - liblzma_rs::common::easy_encoder_memusage::lzma_easy_encoder_memusage(preset) + xz::common::easy_encoder_memusage::lzma_easy_encoder_memusage(preset) } #[no_mangle] pub unsafe extern "C" fn lzma_easy_decoder_memusage(preset: u32) -> u64 { - liblzma_rs::common::easy_decoder_memusage::lzma_easy_decoder_memusage(preset) + xz::common::easy_decoder_memusage::lzma_easy_decoder_memusage(preset) } #[no_mangle] @@ -231,7 +331,7 @@ pub unsafe extern "C" fn lzma_easy_encoder( preset: u32, check: lzma_check, ) -> lzma_ret { - liblzma_rs::common::easy_encoder::lzma_easy_encoder(strm.cast(), preset, check) + xz::common::easy_encoder::lzma_easy_encoder(strm.cast(), preset, check) } #[no_mangle] @@ -245,7 +345,7 @@ pub unsafe extern "C" fn lzma_easy_buffer_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::easy_buffer_encoder::lzma_easy_buffer_encode( + xz::common::easy_buffer_encoder::lzma_easy_buffer_encode( preset, check, allocator.cast(), @@ -257,7 +357,7 @@ pub unsafe extern "C" fn lzma_easy_buffer_encode( ) } -// --- Stream encoder/decoder --- +/* `lzma/container.h`: stream encoder / decoder */ #[no_mangle] pub unsafe extern "C" fn lzma_stream_encoder( @@ -265,7 +365,7 @@ pub unsafe extern "C" fn lzma_stream_encoder( filters: *const lzma_filter, check: lzma_check, ) -> lzma_ret { - liblzma_rs::common::stream_encoder::lzma_stream_encoder(strm.cast(), filters.cast(), check) + xz::common::stream_encoder::lzma_stream_encoder(strm.cast(), filters.cast(), check) } #[no_mangle] @@ -274,25 +374,25 @@ pub unsafe extern "C" fn lzma_stream_decoder( memlimit: u64, flags: u32, ) -> lzma_ret { - liblzma_rs::common::stream_decoder::lzma_stream_decoder(strm.cast(), memlimit, flags) + xz::common::stream_decoder::lzma_stream_decoder(strm.cast(), memlimit, flags) } -// --- Alone encoder/decoder --- +/* `lzma/container.h`: alone encoder / decoder */ #[no_mangle] pub unsafe extern "C" fn lzma_alone_encoder( strm: *mut lzma_stream, options: *const lzma_options_lzma, ) -> lzma_ret { - liblzma_rs::common::alone_encoder::lzma_alone_encoder(strm.cast(), options.cast()) + xz::common::alone_encoder::lzma_alone_encoder(strm.cast(), options.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_alone_decoder(strm: *mut lzma_stream, memlimit: u64) -> lzma_ret { - liblzma_rs::common::alone_decoder::lzma_alone_decoder(strm.cast(), memlimit) + xz::common::alone_decoder::lzma_alone_decoder(strm.cast(), memlimit) } -// --- Auto/lzip decoder --- +/* `lzma/container.h`: auto / lzip decoder */ #[no_mangle] pub unsafe extern "C" fn lzma_auto_decoder( @@ -300,7 +400,7 @@ pub unsafe extern "C" fn lzma_auto_decoder( memlimit: u64, flags: u32, ) -> lzma_ret { - liblzma_rs::common::auto_decoder::lzma_auto_decoder(strm.cast(), memlimit, flags) + xz::common::auto_decoder::lzma_auto_decoder(strm.cast(), memlimit, flags) } #[no_mangle] @@ -309,14 +409,14 @@ pub unsafe extern "C" fn lzma_lzip_decoder( memlimit: u64, flags: u32, ) -> lzma_ret { - liblzma_rs::common::lzip_decoder::lzma_lzip_decoder(strm.cast(), memlimit, flags) + xz::common::lzip_decoder::lzma_lzip_decoder(strm.cast(), memlimit, flags) } -// --- Stream buffer --- +/* `lzma/container.h`: stream buffer */ #[no_mangle] pub unsafe extern "C" fn lzma_stream_buffer_bound(uncompressed_size: size_t) -> size_t { - liblzma_rs::common::stream_buffer_encoder::lzma_stream_buffer_bound(uncompressed_size) + xz::common::stream_buffer_encoder::lzma_stream_buffer_bound(uncompressed_size) } #[no_mangle] @@ -330,7 +430,7 @@ pub unsafe extern "C" fn lzma_stream_buffer_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::stream_buffer_encoder::lzma_stream_buffer_encode( + xz::common::stream_buffer_encoder::lzma_stream_buffer_encode( filters.cast(), check, allocator.cast(), @@ -354,7 +454,7 @@ pub unsafe extern "C" fn lzma_stream_buffer_decode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::stream_buffer_decoder::lzma_stream_buffer_decode( + xz::common::stream_buffer_decoder::lzma_stream_buffer_decode( memlimit, flags, allocator.cast(), @@ -367,16 +467,20 @@ pub unsafe extern "C" fn lzma_stream_buffer_decode( ) } -// --- Filter --- +/*********** + * Filters * + ***********/ + +/* `lzma/filter.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_filter_encoder_is_supported(id: lzma_vli) -> lzma_bool { - liblzma_rs::common::filter_encoder::lzma_filter_encoder_is_supported(id) + xz::common::filter_encoder::lzma_filter_encoder_is_supported(id) } #[no_mangle] pub unsafe extern "C" fn lzma_filter_decoder_is_supported(id: lzma_vli) -> lzma_bool { - liblzma_rs::common::filter_decoder::lzma_filter_decoder_is_supported(id) + xz::common::filter_decoder::lzma_filter_decoder_is_supported(id) } #[no_mangle] @@ -385,17 +489,17 @@ pub unsafe extern "C" fn lzma_filters_copy( dest: *mut lzma_filter, allocator: *const lzma_allocator, ) -> lzma_ret { - liblzma_rs::common::filter_common::lzma_filters_copy(src.cast(), dest.cast(), allocator.cast()) + xz::common::filter_common::lzma_filters_copy(src.cast(), dest.cast(), allocator.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_raw_encoder_memusage(filters: *const lzma_filter) -> u64 { - liblzma_rs::common::filter_encoder::lzma_raw_encoder_memusage(filters.cast()) + xz::common::filter_encoder::lzma_raw_encoder_memusage(filters.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_raw_decoder_memusage(filters: *const lzma_filter) -> u64 { - liblzma_rs::common::filter_decoder::lzma_raw_decoder_memusage(filters.cast()) + xz::common::filter_decoder::lzma_raw_decoder_memusage(filters.cast()) } #[no_mangle] @@ -403,7 +507,7 @@ pub unsafe extern "C" fn lzma_raw_encoder( strm: *mut lzma_stream, filters: *const lzma_filter, ) -> lzma_ret { - liblzma_rs::common::filter_encoder::lzma_raw_encoder(strm.cast(), filters.cast()) + xz::common::filter_encoder::lzma_raw_encoder(strm.cast(), filters.cast()) } #[no_mangle] @@ -411,7 +515,7 @@ pub unsafe extern "C" fn lzma_raw_decoder( strm: *mut lzma_stream, filters: *const lzma_filter, ) -> lzma_ret { - liblzma_rs::common::filter_decoder::lzma_raw_decoder(strm.cast(), filters.cast()) + xz::common::filter_decoder::lzma_raw_decoder(strm.cast(), filters.cast()) } #[no_mangle] @@ -419,10 +523,10 @@ pub unsafe extern "C" fn lzma_filters_update( strm: *mut lzma_stream, filters: *const lzma_filter, ) -> lzma_ret { - liblzma_rs::common::filter_encoder::lzma_filters_update(strm.cast(), filters.cast()) + xz::common::filter_encoder::lzma_filters_update(strm.cast(), filters.cast()) } -// --- Raw buffer --- +/* `lzma/filter.h`: raw buffer */ #[no_mangle] pub unsafe extern "C" fn lzma_raw_buffer_encode( @@ -434,7 +538,7 @@ pub unsafe extern "C" fn lzma_raw_buffer_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::filter_buffer_encoder::lzma_raw_buffer_encode( + xz::common::filter_buffer_encoder::lzma_raw_buffer_encode( filters.cast(), allocator.cast(), input, @@ -456,7 +560,7 @@ pub unsafe extern "C" fn lzma_raw_buffer_decode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::filter_buffer_decoder::lzma_raw_buffer_decode( + xz::common::filter_buffer_decoder::lzma_raw_buffer_decode( filters.cast(), allocator.cast(), input, @@ -468,14 +572,14 @@ pub unsafe extern "C" fn lzma_raw_buffer_decode( ) } -// --- Properties --- +/* `lzma/filter.h`: properties */ #[no_mangle] pub unsafe extern "C" fn lzma_properties_size( size: *mut u32, filter: *const lzma_filter, ) -> lzma_ret { - liblzma_rs::common::filter_encoder::lzma_properties_size(size, filter.cast()) + xz::common::filter_encoder::lzma_properties_size(size, filter.cast()) } #[no_mangle] @@ -483,7 +587,7 @@ pub unsafe extern "C" fn lzma_properties_encode( filter: *const lzma_filter, props: *mut u8, ) -> lzma_ret { - liblzma_rs::common::filter_encoder::lzma_properties_encode(filter.cast(), props) + xz::common::filter_encoder::lzma_properties_encode(filter.cast(), props) } #[no_mangle] @@ -493,7 +597,7 @@ pub unsafe extern "C" fn lzma_properties_decode( props: *const u8, props_size: size_t, ) -> lzma_ret { - liblzma_rs::common::filter_decoder::lzma_properties_decode( + xz::common::filter_decoder::lzma_properties_decode( filter.cast(), allocator.cast(), props, @@ -503,32 +607,97 @@ pub unsafe extern "C" fn lzma_properties_decode( #[no_mangle] pub unsafe extern "C" fn lzma_mt_block_size(filters: *const lzma_filter) -> u64 { - liblzma_rs::common::filter_encoder::lzma_mt_block_size(filters.cast()) + xz::common::filter_encoder::lzma_mt_block_size(filters.cast()) } -// --- LZMA preset --- +/* `lzma/lzma12.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_lzma_preset( options: *mut lzma_options_lzma, preset: u32, ) -> lzma_bool { - liblzma_rs::lzma::lzma_encoder_presets::lzma_lzma_preset(options.cast(), preset) + xz::lzma::lzma_encoder_presets::lzma_lzma_preset(options.cast(), preset) } #[no_mangle] pub unsafe extern "C" fn lzma_mf_is_supported(mf: lzma_match_finder) -> lzma_bool { - liblzma_rs::lz::lz_encoder::lzma_mf_is_supported(mf) + xz::lz::lz_encoder::lzma_mf_is_supported(mf) +} + +#[no_mangle] +pub extern "C" fn lzma_mode_is_supported(mode: lzma_mode) -> lzma_bool { + xz::lzma::lzma_encoder::lzma_mode_is_supported(mode) } -// --- Stream header/footer --- +/* `lzma/bcj.h` */ + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_arm64_encode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::arm64::lzma_bcj_arm64_encode(start_offset, buf, size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_arm64_decode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::arm64::lzma_bcj_arm64_decode(start_offset, buf, size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_riscv_encode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::riscv::lzma_bcj_riscv_encode(start_offset, buf, size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_riscv_decode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::riscv::lzma_bcj_riscv_decode(start_offset, buf, size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_x86_encode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::x86::lzma_bcj_x86_encode(start_offset, buf, size) +} + +#[no_mangle] +pub unsafe extern "C" fn lzma_bcj_x86_decode( + start_offset: u32, + buf: *mut u8, + size: size_t, +) -> size_t { + xz::simple::x86::lzma_bcj_x86_decode(start_offset, buf, size) +} + +/********************* + * Advanced Features * + *********************/ + +/* `lzma/stream_flags.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_stream_header_encode( options: *const lzma_stream_flags, out: *mut u8, ) -> lzma_ret { - liblzma_rs::common::stream_flags_encoder::lzma_stream_header_encode(options.cast(), out) + xz::common::stream_flags_encoder::lzma_stream_header_encode(options.cast(), out) } #[no_mangle] @@ -536,7 +705,7 @@ pub unsafe extern "C" fn lzma_stream_footer_encode( options: *const lzma_stream_flags, out: *mut u8, ) -> lzma_ret { - liblzma_rs::common::stream_flags_encoder::lzma_stream_footer_encode(options.cast(), out) + xz::common::stream_flags_encoder::lzma_stream_footer_encode(options.cast(), out) } #[no_mangle] @@ -544,7 +713,7 @@ pub unsafe extern "C" fn lzma_stream_header_decode( options: *mut lzma_stream_flags, input: *const u8, ) -> lzma_ret { - liblzma_rs::common::stream_flags_decoder::lzma_stream_header_decode(options.cast(), input) + xz::common::stream_flags_decoder::lzma_stream_header_decode(options.cast(), input) } #[no_mangle] @@ -552,7 +721,7 @@ pub unsafe extern "C" fn lzma_stream_footer_decode( options: *mut lzma_stream_flags, input: *const u8, ) -> lzma_ret { - liblzma_rs::common::stream_flags_decoder::lzma_stream_footer_decode(options.cast(), input) + xz::common::stream_flags_decoder::lzma_stream_footer_decode(options.cast(), input) } #[no_mangle] @@ -560,51 +729,22 @@ pub unsafe extern "C" fn lzma_stream_flags_compare( a: *const lzma_stream_flags, b: *const lzma_stream_flags, ) -> lzma_ret { - liblzma_rs::common::stream_flags_common::lzma_stream_flags_compare(a.cast(), b.cast()) + xz::common::stream_flags_common::lzma_stream_flags_compare(a.cast(), b.cast()) } -// --- VLI --- - -#[no_mangle] -pub unsafe extern "C" fn lzma_vli_encode( - vli: lzma_vli, - vli_pos: *mut size_t, - out: *mut u8, - out_pos: *mut size_t, - out_size: size_t, -) -> lzma_ret { - liblzma_rs::common::vli_encoder::lzma_vli_encode(vli, vli_pos, out, out_pos, out_size) -} - -#[no_mangle] -pub unsafe extern "C" fn lzma_vli_decode( - vli: *mut lzma_vli, - vli_pos: *mut size_t, - input: *const u8, - in_pos: *mut size_t, - in_size: size_t, -) -> lzma_ret { - liblzma_rs::common::vli_decoder::lzma_vli_decode(vli, vli_pos, input, in_pos, in_size) -} - -#[no_mangle] -pub unsafe extern "C" fn lzma_vli_size(vli: lzma_vli) -> u32 { - liblzma_rs::common::vli_size::lzma_vli_size(vli) -} - -// --- Hardware --- +/* `lzma/hardware.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_physmem() -> u64 { - liblzma_rs::common::hardware_physmem::lzma_physmem() + xz::common::hardware_physmem::lzma_physmem() } #[no_mangle] pub unsafe extern "C" fn lzma_cputhreads() -> u32 { - liblzma_rs::common::hardware_cputhreads::lzma_cputhreads() + xz::common::hardware_cputhreads::lzma_cputhreads() } -// --- Index --- +/* `lzma/index.h`: core index operations */ #[no_mangle] pub unsafe extern "C" fn lzma_index_buffer_decode( @@ -615,7 +755,7 @@ pub unsafe extern "C" fn lzma_index_buffer_decode( in_pos: *mut size_t, in_size: size_t, ) -> lzma_ret { - liblzma_rs::common::index_decoder::lzma_index_buffer_decode( + xz::common::index_decoder::lzma_index_buffer_decode( i.cast(), memlimit, allocator.cast(), @@ -627,19 +767,19 @@ pub unsafe extern "C" fn lzma_index_buffer_decode( #[no_mangle] pub unsafe extern "C" fn lzma_index_uncompressed_size(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_uncompressed_size(i.cast()) + xz::common::index::lzma_index_uncompressed_size(i.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_end(i: *mut lzma_index, allocator: *const lzma_allocator) { - liblzma_rs::common::index::lzma_index_end(i.cast(), allocator.cast()) + xz::common::index::lzma_index_end(i.cast(), allocator.cast()) } -// --- Block --- +/* `lzma/block.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_block_header_size(block: *mut lzma_block) -> lzma_ret { - liblzma_rs::common::block_header_encoder::lzma_block_header_size(block.cast()) + xz::common::block_header_encoder::lzma_block_header_size(block.cast()) } #[no_mangle] @@ -647,7 +787,7 @@ pub unsafe extern "C" fn lzma_block_header_encode( block: *const lzma_block, out: *mut u8, ) -> lzma_ret { - liblzma_rs::common::block_header_encoder::lzma_block_header_encode(block.cast(), out) + xz::common::block_header_encoder::lzma_block_header_encode(block.cast(), out) } #[no_mangle] @@ -656,7 +796,7 @@ pub unsafe extern "C" fn lzma_block_header_decode( allocator: *const lzma_allocator, input: *const u8, ) -> lzma_ret { - liblzma_rs::common::block_header_decoder::lzma_block_header_decode( + xz::common::block_header_decoder::lzma_block_header_decode( block.cast(), allocator.cast(), input, @@ -668,17 +808,17 @@ pub unsafe extern "C" fn lzma_block_compressed_size( block: *mut lzma_block, unpadded_size: lzma_vli, ) -> lzma_ret { - liblzma_rs::common::block_util::lzma_block_compressed_size(block.cast(), unpadded_size) + xz::common::block_util::lzma_block_compressed_size(block.cast(), unpadded_size) } #[no_mangle] pub unsafe extern "C" fn lzma_block_unpadded_size(block: *const lzma_block) -> lzma_vli { - liblzma_rs::common::block_util::lzma_block_unpadded_size(block.cast()) + xz::common::block_util::lzma_block_unpadded_size(block.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_block_total_size(block: *const lzma_block) -> lzma_vli { - liblzma_rs::common::block_util::lzma_block_total_size(block.cast()) + xz::common::block_util::lzma_block_total_size(block.cast()) } #[no_mangle] @@ -686,7 +826,7 @@ pub unsafe extern "C" fn lzma_block_encoder( strm: *mut lzma_stream, block: *mut lzma_block, ) -> lzma_ret { - liblzma_rs::common::block_encoder::lzma_block_encoder(strm.cast(), block.cast()) + xz::common::block_encoder::lzma_block_encoder(strm.cast(), block.cast()) } #[no_mangle] @@ -694,12 +834,12 @@ pub unsafe extern "C" fn lzma_block_decoder( strm: *mut lzma_stream, block: *mut lzma_block, ) -> lzma_ret { - liblzma_rs::common::block_decoder::lzma_block_decoder(strm.cast(), block.cast()) + xz::common::block_decoder::lzma_block_decoder(strm.cast(), block.cast()) } #[no_mangle] pub extern "C" fn lzma_block_buffer_bound(uncompressed_size: size_t) -> size_t { - liblzma_rs::common::block_buffer_encoder::lzma_block_buffer_bound(uncompressed_size) + xz::common::block_buffer_encoder::lzma_block_buffer_bound(uncompressed_size) } #[no_mangle] @@ -712,7 +852,7 @@ pub unsafe extern "C" fn lzma_block_buffer_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::block_buffer_encoder::lzma_block_buffer_encode( + xz::common::block_buffer_encoder::lzma_block_buffer_encode( block.cast(), allocator.cast(), input, @@ -732,7 +872,7 @@ pub unsafe extern "C" fn lzma_block_uncomp_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::block_buffer_encoder::lzma_block_uncomp_encode( + xz::common::block_buffer_encoder::lzma_block_uncomp_encode( block.cast(), input, in_size, @@ -753,7 +893,7 @@ pub unsafe extern "C" fn lzma_block_buffer_decode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::block_buffer_decoder::lzma_block_buffer_decode( + xz::common::block_buffer_decoder::lzma_block_buffer_decode( block.cast(), allocator.cast(), input, @@ -765,21 +905,21 @@ pub unsafe extern "C" fn lzma_block_buffer_decode( ) } -// --- Index (extended) --- +/* `lzma/index.h`: extended index operations */ #[no_mangle] pub extern "C" fn lzma_index_memusage(streams: lzma_vli, blocks: lzma_vli) -> u64 { - liblzma_rs::common::index::lzma_index_memusage(streams, blocks) + xz::common::index::lzma_index_memusage(streams, blocks) } #[no_mangle] pub extern "C" fn lzma_index_memused(i: *const lzma_index) -> u64 { - liblzma_rs::common::index::lzma_index_memused(i.cast()) + xz::common::index::lzma_index_memused(i.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_init(allocator: *const lzma_allocator) -> *mut lzma_index { - liblzma_rs::common::index::lzma_index_init(allocator.cast()).cast() + xz::common::index::lzma_index_init(allocator.cast()).cast() } #[no_mangle] @@ -789,7 +929,7 @@ pub unsafe extern "C" fn lzma_index_append( unpadded_size: lzma_vli, uncompressed_size: lzma_vli, ) -> lzma_ret { - liblzma_rs::common::index::lzma_index_append( + xz::common::index::lzma_index_append( i.cast(), allocator.cast(), unpadded_size, @@ -802,12 +942,12 @@ pub unsafe extern "C" fn lzma_index_stream_flags( i: *mut lzma_index, stream_flags: *const lzma_stream_flags, ) -> lzma_ret { - liblzma_rs::common::index::lzma_index_stream_flags(i.cast(), stream_flags.cast()) + xz::common::index::lzma_index_stream_flags(i.cast(), stream_flags.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_checks(i: *const lzma_index) -> u32 { - liblzma_rs::common::index::lzma_index_checks(i.cast()) + xz::common::index::lzma_index_checks(i.cast()) } #[no_mangle] @@ -815,47 +955,47 @@ pub unsafe extern "C" fn lzma_index_stream_padding( i: *mut lzma_index, stream_padding: lzma_vli, ) -> lzma_ret { - liblzma_rs::common::index::lzma_index_stream_padding(i.cast(), stream_padding) + xz::common::index::lzma_index_stream_padding(i.cast(), stream_padding) } #[no_mangle] pub extern "C" fn lzma_index_stream_count(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_stream_count(i.cast()) + xz::common::index::lzma_index_stream_count(i.cast()) } #[no_mangle] pub extern "C" fn lzma_index_block_count(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_block_count(i.cast()) + xz::common::index::lzma_index_block_count(i.cast()) } #[no_mangle] pub extern "C" fn lzma_index_size(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_size(i.cast()) + xz::common::index::lzma_index_size(i.cast()) } #[no_mangle] pub extern "C" fn lzma_index_stream_size(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_stream_size(i.cast()) + xz::common::index::lzma_index_stream_size(i.cast()) } #[no_mangle] pub extern "C" fn lzma_index_total_size(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_total_size(i.cast()) + xz::common::index::lzma_index_total_size(i.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_file_size(i: *const lzma_index) -> lzma_vli { - liblzma_rs::common::index::lzma_index_file_size(i.cast()) + xz::common::index::lzma_index_file_size(i.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_iter_init(iter: *mut lzma_index_iter, i: *const lzma_index) { - liblzma_rs::common::index::lzma_index_iter_init(iter.cast(), i.cast()) + xz::common::index::lzma_index_iter_init(iter.cast(), i.cast()) } #[no_mangle] pub unsafe extern "C" fn lzma_index_iter_rewind(iter: *mut lzma_index_iter) { - liblzma_rs::common::index::lzma_index_iter_rewind(iter.cast()) + xz::common::index::lzma_index_iter_rewind(iter.cast()) } #[no_mangle] @@ -863,7 +1003,7 @@ pub unsafe extern "C" fn lzma_index_iter_next( iter: *mut lzma_index_iter, mode: lzma_index_iter_mode, ) -> lzma_bool { - liblzma_rs::common::index::lzma_index_iter_next(iter.cast(), mode) + xz::common::index::lzma_index_iter_next(iter.cast(), mode) } #[no_mangle] @@ -871,7 +1011,7 @@ pub unsafe extern "C" fn lzma_index_iter_locate( iter: *mut lzma_index_iter, target: lzma_vli, ) -> lzma_bool { - liblzma_rs::common::index::lzma_index_iter_locate(iter.cast(), target) + xz::common::index::lzma_index_iter_locate(iter.cast(), target) } #[no_mangle] @@ -880,7 +1020,7 @@ pub unsafe extern "C" fn lzma_index_cat( src: *mut lzma_index, allocator: *const lzma_allocator, ) -> lzma_ret { - liblzma_rs::common::index::lzma_index_cat(dest.cast(), src.cast(), allocator.cast()) + xz::common::index::lzma_index_cat(dest.cast(), src.cast(), allocator.cast()) } #[no_mangle] @@ -888,7 +1028,7 @@ pub unsafe extern "C" fn lzma_index_dup( i: *const lzma_index, allocator: *const lzma_allocator, ) -> *mut lzma_index { - liblzma_rs::common::index::lzma_index_dup(i.cast(), allocator.cast()).cast() + xz::common::index::lzma_index_dup(i.cast(), allocator.cast()).cast() } #[no_mangle] @@ -896,7 +1036,7 @@ pub unsafe extern "C" fn lzma_index_encoder( strm: *mut lzma_stream, i: *const lzma_index, ) -> lzma_ret { - liblzma_rs::common::index_encoder::lzma_index_encoder(strm.cast(), i.cast()) + xz::common::index_encoder::lzma_index_encoder(strm.cast(), i.cast()) } #[no_mangle] @@ -905,7 +1045,7 @@ pub unsafe extern "C" fn lzma_index_decoder( i: *mut *mut lzma_index, memlimit: u64, ) -> lzma_ret { - liblzma_rs::common::index_decoder::lzma_index_decoder(strm.cast(), i.cast(), memlimit) + xz::common::index_decoder::lzma_index_decoder(strm.cast(), i.cast(), memlimit) } #[no_mangle] @@ -915,17 +1055,17 @@ pub unsafe extern "C" fn lzma_index_buffer_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::index_encoder::lzma_index_buffer_encode(i.cast(), out, out_pos, out_size) + xz::common::index_encoder::lzma_index_buffer_encode(i.cast(), out, out_pos, out_size) } -// --- Index hash --- +/* `lzma/index_hash.h` */ #[no_mangle] pub unsafe extern "C" fn lzma_index_hash_init( index_hash: *mut lzma_index_hash, allocator: *const lzma_allocator, ) -> *mut lzma_index_hash { - liblzma_rs::common::index_hash::lzma_index_hash_init(index_hash.cast(), allocator.cast()).cast() + xz::common::index_hash::lzma_index_hash_init(index_hash.cast(), allocator.cast()).cast() } #[no_mangle] @@ -933,7 +1073,7 @@ pub unsafe extern "C" fn lzma_index_hash_end( index_hash: *mut lzma_index_hash, allocator: *const lzma_allocator, ) { - liblzma_rs::common::index_hash::lzma_index_hash_end(index_hash.cast(), allocator.cast()) + xz::common::index_hash::lzma_index_hash_end(index_hash.cast(), allocator.cast()) } #[no_mangle] @@ -942,7 +1082,7 @@ pub unsafe extern "C" fn lzma_index_hash_append( unpadded_size: lzma_vli, uncompressed_size: lzma_vli, ) -> lzma_ret { - liblzma_rs::common::index_hash::lzma_index_hash_append( + xz::common::index_hash::lzma_index_hash_append( index_hash.cast(), unpadded_size, uncompressed_size, @@ -956,27 +1096,22 @@ pub unsafe extern "C" fn lzma_index_hash_decode( in_pos: *mut size_t, in_size: size_t, ) -> lzma_ret { - liblzma_rs::common::index_hash::lzma_index_hash_decode( - index_hash.cast(), - input, - in_pos, - in_size, - ) + xz::common::index_hash::lzma_index_hash_decode(index_hash.cast(), input, in_pos, in_size) } #[no_mangle] pub extern "C" fn lzma_index_hash_size(index_hash: *const lzma_index_hash) -> lzma_vli { - liblzma_rs::common::index_hash::lzma_index_hash_size(index_hash.cast()) + xz::common::index_hash::lzma_index_hash_size(index_hash.cast()) } -// --- Filter flags/string --- +/* `lzma/filter.h`: filter flags / string conversion */ #[no_mangle] pub unsafe extern "C" fn lzma_filter_flags_size( size: *mut u32, filter: *const lzma_filter, ) -> lzma_ret { - liblzma_rs::common::filter_flags_encoder::lzma_filter_flags_size(size, filter.cast()) + xz::common::filter_flags_encoder::lzma_filter_flags_size(size, filter.cast()) } #[no_mangle] @@ -986,7 +1121,7 @@ pub unsafe extern "C" fn lzma_filter_flags_encode( out_pos: *mut size_t, out_size: size_t, ) -> lzma_ret { - liblzma_rs::common::filter_flags_encoder::lzma_filter_flags_encode( + xz::common::filter_flags_encoder::lzma_filter_flags_encode( filter.cast(), out, out_pos, @@ -1002,7 +1137,7 @@ pub unsafe extern "C" fn lzma_filter_flags_decode( in_pos: *mut size_t, in_size: size_t, ) -> lzma_ret { - liblzma_rs::common::filter_flags_decoder::lzma_filter_flags_decode( + xz::common::filter_flags_decoder::lzma_filter_flags_decode( filter.cast(), allocator.cast(), input, @@ -1016,7 +1151,7 @@ pub unsafe extern "C" fn lzma_filters_free( filters: *mut lzma_filter, allocator: *const lzma_allocator, ) { - liblzma_rs::common::filter_common::lzma_filters_free(filters.cast(), allocator.cast()) + xz::common::filter_common::lzma_filters_free(filters.cast(), allocator.cast()) } #[no_mangle] @@ -1027,7 +1162,7 @@ pub unsafe extern "C" fn lzma_str_to_filters( flags: u32, allocator: *const lzma_allocator, ) -> *const c_char { - liblzma_rs::common::string_conversion::lzma_str_to_filters( + xz::common::string_conversion::lzma_str_to_filters( str_, error_pos, filters.cast(), @@ -1043,7 +1178,7 @@ pub unsafe extern "C" fn lzma_str_from_filters( flags: u32, allocator: *const lzma_allocator, ) -> lzma_ret { - liblzma_rs::common::string_conversion::lzma_str_from_filters( + xz::common::string_conversion::lzma_str_from_filters( str_, filters.cast(), flags, @@ -1058,27 +1193,17 @@ pub unsafe extern "C" fn lzma_str_list_filters( flags: u32, allocator: *const lzma_allocator, ) -> lzma_ret { - liblzma_rs::common::string_conversion::lzma_str_list_filters( - str_, - filter_id, - flags, - allocator.cast(), - ) + xz::common::string_conversion::lzma_str_list_filters(str_, filter_id, flags, allocator.cast()) } -// --- Misc --- - -#[no_mangle] -pub extern "C" fn lzma_mode_is_supported(mode: lzma_mode) -> lzma_bool { - liblzma_rs::lzma::lzma_encoder::lzma_mode_is_supported(mode) -} +/* `lzma/container.h`: additional container helpers */ #[no_mangle] pub unsafe extern "C" fn lzma_microlzma_encoder( strm: *mut lzma_stream, options: *const lzma_options_lzma, ) -> lzma_ret { - liblzma_rs::common::microlzma_encoder::lzma_microlzma_encoder(strm.cast(), options.cast()) + xz::common::microlzma_encoder::lzma_microlzma_encoder(strm.cast(), options.cast()) } #[no_mangle] @@ -1089,7 +1214,7 @@ pub unsafe extern "C" fn lzma_microlzma_decoder( uncomp_size_is_exact: lzma_bool, dict_size: u32, ) -> lzma_ret { - liblzma_rs::common::microlzma_decoder::lzma_microlzma_decoder( + xz::common::microlzma_decoder::lzma_microlzma_decoder( strm.cast(), comp_size, uncomp_size, @@ -1105,17 +1230,14 @@ pub unsafe extern "C" fn lzma_file_info_decoder( memlimit: u64, file_size: u64, ) -> lzma_ret { - liblzma_rs::common::file_info::lzma_file_info_decoder( - strm.cast(), - i.cast(), - memlimit, - file_size, - ) + xz::common::file_info::lzma_file_info_decoder(strm.cast(), i.cast(), memlimit, file_size) } -// ========================================================================= -// Multithreaded API -// ========================================================================= +/********************* + * Container Formats * + *********************/ + +/* `lzma/container.h`: multithreaded API */ #[cfg(feature = "parallel")] #[no_mangle] @@ -1123,7 +1245,7 @@ pub unsafe extern "C" fn lzma_stream_encoder_mt( strm: *mut lzma_stream, options: *const lzma_mt, ) -> lzma_ret { - liblzma_rs::common::stream_mt::lzma_stream_encoder_mt(strm.cast(), options.cast()) + xz::common::stream_mt::lzma_stream_encoder_mt(strm.cast(), options.cast()) } #[cfg(feature = "parallel")] @@ -1132,11 +1254,11 @@ pub unsafe extern "C" fn lzma_stream_decoder_mt( strm: *mut lzma_stream, options: *const lzma_mt, ) -> lzma_ret { - liblzma_rs::common::stream_mt::lzma_stream_decoder_mt(strm.cast(), options.cast()) + xz::common::stream_mt::lzma_stream_decoder_mt(strm.cast(), options.cast()) } #[cfg(feature = "parallel")] #[no_mangle] pub unsafe extern "C" fn lzma_stream_encoder_mt_memusage(options: *const lzma_mt) -> u64 { - liblzma_rs::common::stream_mt::lzma_stream_encoder_mt_memusage(options.cast()) + xz::common::stream_mt::lzma_stream_encoder_mt_memusage(options.cast()) } diff --git a/liblzma-rs/Cargo.toml b/xz/Cargo.toml similarity index 95% rename from liblzma-rs/Cargo.toml rename to xz/Cargo.toml index 0db47bbf..8495c3fd 100644 --- a/liblzma-rs/Cargo.toml +++ b/xz/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "liblzma-rs" +name = "xz" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" diff --git a/liblzma-rs/src/alloc.rs b/xz/src/alloc.rs similarity index 97% rename from liblzma-rs/src/alloc.rs rename to xz/src/alloc.rs index 00f8a9ff..1b73e3a3 100644 --- a/liblzma-rs/src/alloc.rs +++ b/xz/src/alloc.rs @@ -64,7 +64,7 @@ unsafe fn rust_free_impl(ptr: *mut c_void) { dealloc(base, layout); } -pub unsafe extern "C" fn lzma_rust_alloc( +pub(crate) unsafe extern "C" fn lzma_rust_alloc( _opaque: *mut c_void, nmemb: size_t, size: size_t, @@ -76,7 +76,7 @@ pub unsafe extern "C" fn lzma_rust_alloc( rust_alloc_impl(size, RUST_ALLOC_ALIGN, false) } -pub unsafe extern "C" fn lzma_rust_free(_opaque: *mut c_void, ptr: *mut c_void) { +pub(crate) unsafe extern "C" fn lzma_rust_free(_opaque: *mut c_void, ptr: *mut c_void) { rust_free_impl(ptr); } diff --git a/liblzma-rs/src/check/check.rs b/xz/src/check/check.rs similarity index 100% rename from liblzma-rs/src/check/check.rs rename to xz/src/check/check.rs diff --git a/liblzma-rs/src/check/crc32_fast.rs b/xz/src/check/crc32_fast.rs similarity index 93% rename from liblzma-rs/src/check/crc32_fast.rs rename to xz/src/check/crc32_fast.rs index b27f1e92..4ed3553f 100644 --- a/liblzma-rs/src/check/crc32_fast.rs +++ b/xz/src/check/crc32_fast.rs @@ -1,4 +1,7 @@ use crate::types::*; + +#[cfg(target_arch = "aarch64")] +use core::arch::aarch64::{__crc32b, __crc32d, __crc32h, __crc32w}; pub static lzma_crc32_table: [[u32; 256]; 8] = [ [ 0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, @@ -350,6 +353,83 @@ unsafe fn lzma_crc32_generic(mut buf: *const u8, mut size: size_t, mut crc: u32) } !crc } + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +unsafe fn aligned_read16le(buf: *const u8) -> u16 { + core::ptr::read_unaligned(buf as *const u16) +} + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +unsafe fn aligned_read32le(buf: *const u8) -> u32 { + core::ptr::read_unaligned(buf as *const u32) +} + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +unsafe fn aligned_read64le(buf: *const u8) -> u64 { + core::ptr::read_unaligned(buf as *const u64) +} + +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "crc")] +unsafe fn lzma_crc32_arm64(mut buf: *const u8, mut size: size_t, mut crc: u32) -> u32 { + crc = !crc; + + if size >= 8 { + let align = (0usize.wrapping_sub(buf as usize)) & 7; + + if align & 1 != 0 { + crc = __crc32b(crc, *buf); + buf = buf.add(1); + } + + if align & 2 != 0 { + crc = __crc32h(crc, aligned_read16le(buf)); + buf = buf.add(2); + } + + if align & 4 != 0 { + crc = __crc32w(crc, aligned_read32le(buf)); + buf = buf.add(4); + } + + size -= align; + + let limit = buf.add(size & !7); + while buf < limit { + crc = __crc32d(crc, aligned_read64le(buf)); + buf = buf.add(8); + } + + size &= 7; + } + + if size & 4 != 0 { + crc = __crc32w(crc, aligned_read32le(buf)); + buf = buf.add(4); + } + + if size & 2 != 0 { + crc = __crc32h(crc, aligned_read16le(buf)); + buf = buf.add(2); + } + + if size & 1 != 0 { + crc = __crc32b(crc, *buf); + } + + !crc +} + pub unsafe fn lzma_crc32(buf: *const u8, size: size_t, crc: u32) -> u32 { + #[cfg(target_arch = "aarch64")] + { + if std::arch::is_aarch64_feature_detected!("crc") { + return lzma_crc32_arm64(buf, size, crc); + } + } + lzma_crc32_generic(buf, size, crc) } diff --git a/liblzma-rs/src/check/crc64_fast.rs b/xz/src/check/crc64_fast.rs similarity index 95% rename from liblzma-rs/src/check/crc64_fast.rs rename to xz/src/check/crc64_fast.rs index 16bef208..791d5684 100644 --- a/liblzma-rs/src/check/crc64_fast.rs +++ b/xz/src/check/crc64_fast.rs @@ -1,5 +1,5 @@ use crate::types::*; -pub static mut lzma_crc64_table: [[u64; 256]; 4] = [ +pub static lzma_crc64_table: [[u64; 256]; 4] = [ [ 0, 0xb32e4cbe03a75f6f, @@ -1033,31 +1033,59 @@ pub static mut lzma_crc64_table: [[u64; 256]; 4] = [ 0x1e5cd90c6ec2440d, ], ]; -#[inline] +#[inline(always)] +unsafe fn crc64_step4( + table0: *const u64, + table1: *const u64, + table2: *const u64, + table3: *const u64, + buf: *const u8, + crc: u64, +) -> u64 { + let tmp = crc as u32 ^ aligned_read32ne(buf); + *table3.add((tmp & 0xff) as usize) + ^ *table2.add((tmp >> 8 & 0xff) as usize) + ^ crc >> 32 + ^ *table1.add((tmp >> 16 & 0xff) as usize) + ^ *table0.add((tmp >> 24) as usize) +} + +#[inline(always)] unsafe fn lzma_crc64_generic(mut buf: *const u8, mut size: size_t, mut crc: u64) -> u64 { + let table0 = lzma_crc64_table[0].as_ptr(); + let table1 = lzma_crc64_table[1].as_ptr(); + let table2 = lzma_crc64_table[2].as_ptr(); + let table3 = lzma_crc64_table[3].as_ptr(); crc = !crc; if size > 4 { while buf as uintptr_t & 3 as uintptr_t != 0 { - crc = lzma_crc64_table[0][(*buf as u64 ^ crc & 0xff as u64) as usize] ^ crc >> 8; + crc = *table0.add((*buf as u64 ^ crc & 0xff as u64) as usize) ^ crc >> 8; buf = buf.offset(1); size -= 1; } - let limit: *const u8 = buf.offset((size & !(3)) as isize); - size &= 3; - while buf < limit { - let tmp: u32 = crc as u32 ^ aligned_read32ne(buf) as u32; + let limit8 = buf.offset((size & !(7)) as isize); + while buf < limit8 { + crc = crc64_step4(table0, table1, table2, table3, buf, crc); + buf = buf.offset(4); + crc = crc64_step4(table0, table1, table2, table3, buf, crc); buf = buf.offset(4); - crc = lzma_crc64_table[3][(tmp & 0xff) as usize] - ^ lzma_crc64_table[2][(tmp >> 8 & 0xff) as usize] - ^ crc >> 32 - ^ lzma_crc64_table[1][(tmp >> 16 & 0xff) as usize] - ^ lzma_crc64_table[0][(tmp >> 24) as usize]; } + + if size & 4 != 0 { + crc = crc64_step4(table0, table1, table2, table3, buf, crc); + buf = buf.offset(4); + } + + size &= 3; } - while size > 0 { - crc = lzma_crc64_table[0][(*buf as u64 ^ crc & 0xff as u64) as usize] ^ crc >> 8; + loop { + let old_size = size; + size = size.wrapping_sub(1); + if old_size == 0 { + break; + } + crc = *table0.add((*buf as u64 ^ crc & 0xff as u64) as usize) ^ crc >> 8; buf = buf.offset(1); - size -= 1; } !crc } diff --git a/liblzma-rs/src/check/mod.rs b/xz/src/check/mod.rs similarity index 100% rename from liblzma-rs/src/check/mod.rs rename to xz/src/check/mod.rs diff --git a/liblzma-rs/src/check/sha256.rs b/xz/src/check/sha256.rs similarity index 99% rename from liblzma-rs/src/check/sha256.rs rename to xz/src/check/sha256.rs index f9b8de44..27a825ae 100644 --- a/liblzma-rs/src/check/sha256.rs +++ b/xz/src/check/sha256.rs @@ -1,6 +1,6 @@ use crate::types::*; #[inline] -extern "C" fn rotr_32(num: u32, amount: c_uint) -> u32 { +fn rotr_32(num: u32, amount: c_uint) -> u32 { num >> amount | num << 32u32.wrapping_sub(amount) } static mut SHA256_K: [u32; 64] = [ diff --git a/liblzma-rs/src/common/alone_decoder.rs b/xz/src/common/alone_decoder.rs similarity index 99% rename from liblzma-rs/src/common/alone_decoder.rs rename to xz/src/common/alone_decoder.rs index 31de9d99..894c0d6f 100644 --- a/liblzma-rs/src/common/alone_decoder.rs +++ b/xz/src/common/alone_decoder.rs @@ -173,7 +173,7 @@ unsafe extern "C" fn alone_decoder_memconfig( } LZMA_OK } -pub unsafe extern "C" fn lzma_alone_decoder_init( +pub(crate) unsafe extern "C" fn lzma_alone_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, memlimit: u64, diff --git a/liblzma-rs/src/common/alone_encoder.rs b/xz/src/common/alone_encoder.rs similarity index 100% rename from liblzma-rs/src/common/alone_encoder.rs rename to xz/src/common/alone_encoder.rs diff --git a/liblzma-rs/src/common/auto_decoder.rs b/xz/src/common/auto_decoder.rs similarity index 100% rename from liblzma-rs/src/common/auto_decoder.rs rename to xz/src/common/auto_decoder.rs diff --git a/liblzma-rs/src/common/block_buffer_decoder.rs b/xz/src/common/block_buffer_decoder.rs similarity index 100% rename from liblzma-rs/src/common/block_buffer_decoder.rs rename to xz/src/common/block_buffer_decoder.rs diff --git a/liblzma-rs/src/common/block_buffer_encoder.rs b/xz/src/common/block_buffer_encoder.rs similarity index 99% rename from liblzma-rs/src/common/block_buffer_encoder.rs rename to xz/src/common/block_buffer_encoder.rs index 1c9a8381..db4bb997 100644 --- a/liblzma-rs/src/common/block_buffer_encoder.rs +++ b/xz/src/common/block_buffer_encoder.rs @@ -1,7 +1,7 @@ use crate::types::*; pub const HEADERS_BOUND: u32 = 1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 3 + 4 + LZMA_CHECK_SIZE_MAX + 3 & !(3); -extern "C" fn lzma2_bound(uncompressed_size: u64) -> u64 { +fn lzma2_bound(uncompressed_size: u64) -> u64 { if uncompressed_size > COMPRESSED_SIZE_MAX as u64 { return 0; } diff --git a/liblzma-rs/src/common/block_decoder.rs b/xz/src/common/block_decoder.rs similarity index 98% rename from liblzma-rs/src/common/block_decoder.rs rename to xz/src/common/block_decoder.rs index 90ea969e..61f1c331 100644 --- a/liblzma-rs/src/common/block_decoder.rs +++ b/xz/src/common/block_decoder.rs @@ -18,7 +18,7 @@ pub const SEQ_CHECK: block_decoder_seq = 2; pub const SEQ_PADDING: block_decoder_seq = 1; pub const SEQ_CODE: block_decoder_seq = 0; #[inline] -extern "C" fn is_size_valid(size: lzma_vli, reference: lzma_vli) -> bool { +fn is_size_valid(size: lzma_vli, reference: lzma_vli) -> bool { reference == LZMA_VLI_UNKNOWN || reference == size } unsafe extern "C" fn block_decode( @@ -162,7 +162,7 @@ unsafe extern "C" fn block_decoder_end(coder_ptr: *mut c_void, allocator: *const lzma_next_end(::core::ptr::addr_of_mut!((*coder).next), allocator); crate::alloc::internal_free(coder as *mut c_void, allocator); } -pub unsafe extern "C" fn lzma_block_decoder_init( +pub(crate) unsafe extern "C" fn lzma_block_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, block: *mut lzma_block, diff --git a/liblzma-rs/src/common/block_encoder.rs b/xz/src/common/block_encoder.rs similarity index 99% rename from liblzma-rs/src/common/block_encoder.rs rename to xz/src/common/block_encoder.rs index 25c6ac1f..2d4d068a 100644 --- a/liblzma-rs/src/common/block_encoder.rs +++ b/xz/src/common/block_encoder.rs @@ -131,7 +131,7 @@ unsafe extern "C" fn block_encoder_update( reversed_filters, ) } -pub unsafe extern "C" fn lzma_block_encoder_init( +pub(crate) unsafe extern "C" fn lzma_block_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, block: *mut lzma_block, diff --git a/liblzma-rs/src/common/block_header_decoder.rs b/xz/src/common/block_header_decoder.rs similarity index 100% rename from liblzma-rs/src/common/block_header_decoder.rs rename to xz/src/common/block_header_decoder.rs diff --git a/liblzma-rs/src/common/block_header_encoder.rs b/xz/src/common/block_header_encoder.rs similarity index 100% rename from liblzma-rs/src/common/block_header_encoder.rs rename to xz/src/common/block_header_encoder.rs diff --git a/liblzma-rs/src/common/block_util.rs b/xz/src/common/block_util.rs similarity index 100% rename from liblzma-rs/src/common/block_util.rs rename to xz/src/common/block_util.rs diff --git a/liblzma-rs/src/common/common.rs b/xz/src/common/common.rs similarity index 98% rename from liblzma-rs/src/common/common.rs rename to xz/src/common/common.rs index cde83adb..ca6108f6 100644 --- a/liblzma-rs/src/common/common.rs +++ b/xz/src/common/common.rs @@ -120,9 +120,10 @@ pub unsafe fn lzma_bufcpy( out_pos: *mut size_t, out_size: size_t, ) -> size_t { - if *in_pos > in_size || *out_pos > out_size { - return 0; - } + debug_assert!(!in_0.is_null() || *in_pos == in_size); + debug_assert!(!out.is_null() || *out_pos == out_size); + debug_assert!(*in_pos <= in_size); + debug_assert!(*out_pos <= out_size); let in_avail: size_t = in_size - *in_pos; let out_avail: size_t = out_size - *out_pos; diff --git a/xz/src/common/easy_buffer_encoder.rs b/xz/src/common/easy_buffer_encoder.rs new file mode 100644 index 00000000..a77ccfd4 --- /dev/null +++ b/xz/src/common/easy_buffer_encoder.rs @@ -0,0 +1,29 @@ +use crate::common::stream_buffer_encoder::lzma_stream_buffer_encode; +use crate::types::*; +use core::mem::MaybeUninit; +pub unsafe fn lzma_easy_buffer_encode( + preset: u32, + check: lzma_check, + allocator: *const lzma_allocator, + in_0: *const u8, + in_size: size_t, + out: *mut u8, + out_pos: *mut size_t, + out_size: size_t, +) -> lzma_ret { + let mut opt_easy = MaybeUninit::::uninit(); + if lzma_easy_preset(opt_easy.as_mut_ptr(), preset) { + return LZMA_OPTIONS_ERROR; + } + let opt_easy = opt_easy.assume_init_mut(); + lzma_stream_buffer_encode( + ::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter, + check, + allocator, + in_0, + in_size, + out, + out_pos, + out_size, + ) +} diff --git a/xz/src/common/easy_decoder_memusage.rs b/xz/src/common/easy_decoder_memusage.rs new file mode 100644 index 00000000..fd6ef2e8 --- /dev/null +++ b/xz/src/common/easy_decoder_memusage.rs @@ -0,0 +1,12 @@ +use crate::types::*; +use core::mem::MaybeUninit; +pub fn lzma_easy_decoder_memusage(preset: u32) -> u64 { + let mut opt_easy = MaybeUninit::::uninit(); + if unsafe { lzma_easy_preset(opt_easy.as_mut_ptr(), preset) } { + return UINT32_MAX as u64; + } + let opt_easy = unsafe { opt_easy.assume_init_mut() }; + unsafe { + lzma_raw_decoder_memusage(::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter) + } +} diff --git a/xz/src/common/easy_encoder.rs b/xz/src/common/easy_encoder.rs new file mode 100644 index 00000000..dae8a63d --- /dev/null +++ b/xz/src/common/easy_encoder.rs @@ -0,0 +1,19 @@ +use crate::common::stream_encoder::lzma_stream_encoder; +use crate::types::*; +use core::mem::MaybeUninit; +pub unsafe fn lzma_easy_encoder( + strm: *mut lzma_stream, + preset: u32, + check: lzma_check, +) -> lzma_ret { + let mut opt_easy = MaybeUninit::::uninit(); + if lzma_easy_preset(opt_easy.as_mut_ptr(), preset) { + return LZMA_OPTIONS_ERROR; + } + let opt_easy = opt_easy.assume_init_mut(); + lzma_stream_encoder( + strm, + ::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter, + check, + ) +} diff --git a/xz/src/common/easy_encoder_memusage.rs b/xz/src/common/easy_encoder_memusage.rs new file mode 100644 index 00000000..fca21d26 --- /dev/null +++ b/xz/src/common/easy_encoder_memusage.rs @@ -0,0 +1,12 @@ +use crate::types::*; +use core::mem::MaybeUninit; +pub fn lzma_easy_encoder_memusage(preset: u32) -> u64 { + let mut opt_easy = MaybeUninit::::uninit(); + if unsafe { lzma_easy_preset(opt_easy.as_mut_ptr(), preset) } { + return UINT32_MAX as u64; + } + let opt_easy = unsafe { opt_easy.assume_init_mut() }; + unsafe { + lzma_raw_encoder_memusage(::core::ptr::addr_of_mut!(opt_easy.filters) as *mut lzma_filter) + } +} diff --git a/liblzma-rs/src/common/easy_preset.rs b/xz/src/common/easy_preset.rs similarity index 100% rename from liblzma-rs/src/common/easy_preset.rs rename to xz/src/common/easy_preset.rs diff --git a/liblzma-rs/src/common/file_info.rs b/xz/src/common/file_info.rs similarity index 99% rename from liblzma-rs/src/common/file_info.rs rename to xz/src/common/file_info.rs index e9429322..4b88e4d8 100644 --- a/liblzma-rs/src/common/file_info.rs +++ b/xz/src/common/file_info.rs @@ -110,7 +110,7 @@ unsafe fn get_padding_size(buf: *const u8, mut buf_size: size_t) -> size_t { } padding } -extern "C" fn hide_format_error(mut ret: lzma_ret) -> lzma_ret { +fn hide_format_error(mut ret: lzma_ret) -> lzma_ret { if ret == LZMA_FORMAT_ERROR { ret = LZMA_DATA_ERROR; } diff --git a/liblzma-rs/src/common/filter_buffer_decoder.rs b/xz/src/common/filter_buffer_decoder.rs similarity index 100% rename from liblzma-rs/src/common/filter_buffer_decoder.rs rename to xz/src/common/filter_buffer_decoder.rs diff --git a/liblzma-rs/src/common/filter_buffer_encoder.rs b/xz/src/common/filter_buffer_encoder.rs similarity index 100% rename from liblzma-rs/src/common/filter_buffer_encoder.rs rename to xz/src/common/filter_buffer_encoder.rs diff --git a/liblzma-rs/src/common/filter_common.rs b/xz/src/common/filter_common.rs similarity index 100% rename from liblzma-rs/src/common/filter_common.rs rename to xz/src/common/filter_common.rs diff --git a/liblzma-rs/src/common/filter_decoder.rs b/xz/src/common/filter_decoder.rs similarity index 98% rename from liblzma-rs/src/common/filter_decoder.rs rename to xz/src/common/filter_decoder.rs index fa841b36..2135574c 100644 --- a/liblzma-rs/src/common/filter_decoder.rs +++ b/xz/src/common/filter_decoder.rs @@ -282,7 +282,7 @@ static decoders: [lzma_filter_decoder; 12] = [ ), }, ]; -extern "C" fn decoder_find(id: lzma_vli) -> *const lzma_filter_decoder { +fn decoder_find(id: lzma_vli) -> *const lzma_filter_decoder { let mut i: size_t = 0; while i < core::mem::size_of::<[lzma_filter_decoder; 12]>() / core::mem::size_of::() @@ -294,7 +294,7 @@ extern "C" fn decoder_find(id: lzma_vli) -> *const lzma_filter_decoder { } core::ptr::null() } -extern "C" fn coder_find(id: lzma_vli) -> *const lzma_filter_coder { +unsafe extern "C" fn coder_find(id: lzma_vli) -> *const lzma_filter_coder { decoder_find(id) as *const lzma_filter_coder } pub fn lzma_filter_decoder_is_supported(id: lzma_vli) -> lzma_bool { diff --git a/liblzma-rs/src/common/filter_encoder.rs b/xz/src/common/filter_encoder.rs similarity index 98% rename from liblzma-rs/src/common/filter_encoder.rs rename to xz/src/common/filter_encoder.rs index 82deffa9..dcbd5dbd 100644 --- a/liblzma-rs/src/common/filter_encoder.rs +++ b/xz/src/common/filter_encoder.rs @@ -259,7 +259,7 @@ static encoders: [lzma_filter_encoder; 12] = [ ), }, ]; -extern "C" fn encoder_find(id: lzma_vli) -> *const lzma_filter_encoder { +fn encoder_find(id: lzma_vli) -> *const lzma_filter_encoder { let mut i: size_t = 0; while i < core::mem::size_of::<[lzma_filter_encoder; 12]>() / core::mem::size_of::() @@ -271,7 +271,7 @@ extern "C" fn encoder_find(id: lzma_vli) -> *const lzma_filter_encoder { } core::ptr::null() } -extern "C" fn coder_find(id: lzma_vli) -> *const lzma_filter_coder { +unsafe extern "C" fn coder_find(id: lzma_vli) -> *const lzma_filter_coder { encoder_find(id) as *const lzma_filter_coder } pub fn lzma_filter_encoder_is_supported(id: lzma_vli) -> lzma_bool { diff --git a/liblzma-rs/src/common/filter_flags_decoder.rs b/xz/src/common/filter_flags_decoder.rs similarity index 100% rename from liblzma-rs/src/common/filter_flags_decoder.rs rename to xz/src/common/filter_flags_decoder.rs diff --git a/liblzma-rs/src/common/filter_flags_encoder.rs b/xz/src/common/filter_flags_encoder.rs similarity index 100% rename from liblzma-rs/src/common/filter_flags_encoder.rs rename to xz/src/common/filter_flags_encoder.rs diff --git a/liblzma-rs/src/common/hardware_cputhreads.rs b/xz/src/common/hardware_cputhreads.rs similarity index 100% rename from liblzma-rs/src/common/hardware_cputhreads.rs rename to xz/src/common/hardware_cputhreads.rs diff --git a/liblzma-rs/src/common/hardware_physmem.rs b/xz/src/common/hardware_physmem.rs similarity index 100% rename from liblzma-rs/src/common/hardware_physmem.rs rename to xz/src/common/hardware_physmem.rs diff --git a/liblzma-rs/src/common/index.rs b/xz/src/common/index.rs similarity index 98% rename from liblzma-rs/src/common/index.rs rename to xz/src/common/index.rs index 079c06bc..ec1d6643 100644 --- a/liblzma-rs/src/common/index.rs +++ b/xz/src/common/index.rs @@ -76,11 +76,11 @@ pub struct index_cat_info { pub type iter_mode = c_uint; pub type iter_method = c_uint; #[inline] -extern "C" fn bsr32(n: u32) -> u32 { +fn bsr32(n: u32) -> u32 { n.leading_zeros() as i32 as u32 ^ 31 } #[inline] -extern "C" fn ctz32(n: u32) -> u32 { +fn ctz32(n: u32) -> u32 { n.trailing_zeros() as i32 as u32 } pub const INDEX_GROUP_SIZE: u32 = 512; @@ -96,7 +96,7 @@ unsafe fn index_tree_init(tree: *mut index_tree) { unsafe fn index_tree_node_end( node: *mut index_tree_node, allocator: *const lzma_allocator, - free_func: Option ()>, + free_func: Option ()>, ) { if !(*node).left.is_null() { index_tree_node_end((*node).left, allocator, free_func); @@ -109,12 +109,15 @@ unsafe fn index_tree_node_end( unsafe fn index_tree_end( tree: *mut index_tree, allocator: *const lzma_allocator, - free_func: Option ()>, + free_func: Option ()>, ) { if !(*tree).root.is_null() { index_tree_node_end((*tree).root, allocator, free_func); } } +unsafe fn index_node_free(node: *mut c_void, allocator: *const lzma_allocator) { + lzma_free(node, allocator); +} unsafe fn index_tree_append(tree: *mut index_tree, mut node: *mut index_tree_node) { (*node).parent = (*tree).rightmost; (*node).left = core::ptr::null_mut(); @@ -205,12 +208,12 @@ unsafe fn index_stream_init( (*s).stream_padding = 0; s } -unsafe extern "C" fn index_stream_end(node: *mut c_void, allocator: *const lzma_allocator) { +unsafe fn index_stream_end(node: *mut c_void, allocator: *const lzma_allocator) { let s: *mut index_stream = node as *mut index_stream; index_tree_end( ::core::ptr::addr_of_mut!((*s).groups), allocator, - Some(lzma_free as unsafe extern "C" fn(*mut c_void, *const lzma_allocator) -> ()), + Some(index_node_free as unsafe fn(*mut c_void, *const lzma_allocator) -> ()), ); lzma_free(s as *mut c_void, allocator); } @@ -249,9 +252,7 @@ pub unsafe fn lzma_index_end(i: *mut lzma_index, allocator: *const lzma_allocato index_tree_end( ::core::ptr::addr_of_mut!((*i).streams), allocator, - Some( - index_stream_end as unsafe extern "C" fn(*mut c_void, *const lzma_allocator) -> (), - ), + Some(index_stream_end as unsafe fn(*mut c_void, *const lzma_allocator) -> ()), ); lzma_free(i as *mut c_void, allocator); } diff --git a/liblzma-rs/src/common/index_decoder.rs b/xz/src/common/index_decoder.rs similarity index 99% rename from liblzma-rs/src/common/index_decoder.rs rename to xz/src/common/index_decoder.rs index 99950371..69d824c5 100644 --- a/liblzma-rs/src/common/index_decoder.rs +++ b/xz/src/common/index_decoder.rs @@ -224,7 +224,7 @@ unsafe fn index_decoder_reset( (*coder).crc32 = 0; LZMA_OK } -pub unsafe extern "C" fn lzma_index_decoder_init( +pub(crate) unsafe extern "C" fn lzma_index_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, i: *mut *mut lzma_index, diff --git a/liblzma-rs/src/common/index_encoder.rs b/xz/src/common/index_encoder.rs similarity index 99% rename from liblzma-rs/src/common/index_encoder.rs rename to xz/src/common/index_encoder.rs index e71ad6e2..8b27986a 100644 --- a/liblzma-rs/src/common/index_encoder.rs +++ b/xz/src/common/index_encoder.rs @@ -149,7 +149,7 @@ unsafe fn index_encoder_reset(coder: *mut lzma_index_coder, i: *const lzma_index (*coder).pos = 0; (*coder).crc32 = 0; } -pub unsafe extern "C" fn lzma_index_encoder_init( +pub(crate) unsafe extern "C" fn lzma_index_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, i: *const lzma_index, diff --git a/liblzma-rs/src/common/index_hash.rs b/xz/src/common/index_hash.rs similarity index 99% rename from liblzma-rs/src/common/index_hash.rs rename to xz/src/common/index_hash.rs index c75d4389..1f0ceaf5 100644 --- a/liblzma-rs/src/common/index_hash.rs +++ b/xz/src/common/index_hash.rs @@ -30,7 +30,7 @@ pub const SEQ_COUNT: index_hash_seq = 1; pub const SEQ_BLOCK: index_hash_seq = 0; pub type lzma_index_hash = lzma_index_hash_s; #[inline] -extern "C" fn index_stream_size( +fn index_stream_size( blocks_size: lzma_vli, count: lzma_vli, index_list_size: lzma_vli, diff --git a/liblzma-rs/src/common/lzip_decoder.rs b/xz/src/common/lzip_decoder.rs similarity index 99% rename from liblzma-rs/src/common/lzip_decoder.rs rename to xz/src/common/lzip_decoder.rs index e74bd324..9e8c95ee 100644 --- a/liblzma-rs/src/common/lzip_decoder.rs +++ b/xz/src/common/lzip_decoder.rs @@ -26,7 +26,7 @@ pub const SEQ_DICT_SIZE: lzip_decoder_seq = 2; pub const SEQ_VERSION: lzip_decoder_seq = 1; pub const SEQ_ID_STRING: lzip_decoder_seq = 0; #[inline] -extern "C" fn read64le(buf: *const u8) -> u64 { +fn read64le(buf: *const u8) -> u64 { return unsafe { let mut num: u64 = *buf as u64; num |= (*buf.offset(1) as u64) << 8; @@ -290,7 +290,7 @@ unsafe extern "C" fn lzip_decoder_memconfig( } LZMA_OK } -pub unsafe extern "C" fn lzma_lzip_decoder_init( +pub(crate) unsafe extern "C" fn lzma_lzip_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, memlimit: u64, diff --git a/liblzma-rs/src/common/microlzma_decoder.rs b/xz/src/common/microlzma_decoder.rs similarity index 100% rename from liblzma-rs/src/common/microlzma_decoder.rs rename to xz/src/common/microlzma_decoder.rs diff --git a/liblzma-rs/src/common/microlzma_encoder.rs b/xz/src/common/microlzma_encoder.rs similarity index 100% rename from liblzma-rs/src/common/microlzma_encoder.rs rename to xz/src/common/microlzma_encoder.rs diff --git a/liblzma-rs/src/common/mod.rs b/xz/src/common/mod.rs similarity index 100% rename from liblzma-rs/src/common/mod.rs rename to xz/src/common/mod.rs diff --git a/liblzma-rs/src/common/outqueue.rs b/xz/src/common/outqueue.rs similarity index 100% rename from liblzma-rs/src/common/outqueue.rs rename to xz/src/common/outqueue.rs diff --git a/liblzma-rs/src/common/stream_buffer_decoder.rs b/xz/src/common/stream_buffer_decoder.rs similarity index 100% rename from liblzma-rs/src/common/stream_buffer_decoder.rs rename to xz/src/common/stream_buffer_decoder.rs diff --git a/liblzma-rs/src/common/stream_buffer_encoder.rs b/xz/src/common/stream_buffer_encoder.rs similarity index 100% rename from liblzma-rs/src/common/stream_buffer_encoder.rs rename to xz/src/common/stream_buffer_encoder.rs diff --git a/liblzma-rs/src/common/stream_decoder.rs b/xz/src/common/stream_decoder.rs similarity index 91% rename from liblzma-rs/src/common/stream_decoder.rs rename to xz/src/common/stream_decoder.rs index e8663905..70071fcc 100644 --- a/liblzma-rs/src/common/stream_decoder.rs +++ b/xz/src/common/stream_decoder.rs @@ -1,4 +1,5 @@ use crate::types::*; +use core::mem::MaybeUninit; #[derive(Copy, Clone)] #[repr(C)] pub struct lzma_stream_coder { @@ -172,27 +173,9 @@ unsafe extern "C" fn stream_decode( return LZMA_OK; } (*coder).pos = 0; - let mut footer_flags: lzma_stream_flags = lzma_stream_flags { - version: 0, - backward_size: 0, - check: LZMA_CHECK_NONE, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_bool1: 0, - reserved_bool2: 0, - reserved_bool3: 0, - reserved_bool4: 0, - reserved_bool5: 0, - reserved_bool6: 0, - reserved_bool7: 0, - reserved_bool8: 0, - reserved_int1: 0, - reserved_int2: 0, - }; + let mut footer_flags = MaybeUninit::::uninit(); let ret_3: lzma_ret = lzma_stream_footer_decode( - ::core::ptr::addr_of_mut!(footer_flags), + footer_flags.as_mut_ptr(), ::core::ptr::addr_of_mut!((*coder).buffer) as *mut u8, ); if ret_3 != LZMA_OK { @@ -202,6 +185,7 @@ unsafe extern "C" fn stream_decode( ret_3 }; } + let mut footer_flags = footer_flags.assume_init(); if lzma_index_hash_size((*coder).index_hash) != footer_flags.backward_size { return LZMA_DATA_ERROR; } @@ -251,12 +235,9 @@ unsafe extern "C" fn stream_decode( } 3500765272169221397 => { (*coder).block_options.version = 1; - let mut filters: [lzma_filter; 5] = [lzma_filter { - id: 0, - options: core::ptr::null_mut(), - }; 5]; - (*coder).block_options.filters = - ::core::ptr::addr_of_mut!(filters) as *mut lzma_filter; + let mut filters = MaybeUninit::<[lzma_filter; 5]>::uninit(); + let filters_ptr = filters.as_mut_ptr() as *mut lzma_filter; + (*coder).block_options.filters = filters_ptr; let ret_: lzma_ret = lzma_block_header_decode( ::core::ptr::addr_of_mut!((*coder).block_options), allocator, @@ -266,9 +247,7 @@ unsafe extern "C" fn stream_decode( return ret_; } (*coder).block_options.ignore_check = (*coder).ignore_check as lzma_bool; - let memusage: u64 = lzma_raw_decoder_memusage( - ::core::ptr::addr_of_mut!(filters) as *mut lzma_filter - ) as u64; + let memusage: u64 = lzma_raw_decoder_memusage(filters_ptr) as u64; let mut ret_0: lzma_ret = LZMA_OK; if memusage == UINT64_MAX { ret_0 = LZMA_OPTIONS_ERROR; @@ -284,10 +263,7 @@ unsafe extern "C" fn stream_decode( ); } } - lzma_filters_free( - ::core::ptr::addr_of_mut!(filters) as *mut lzma_filter, - allocator, - ); + lzma_filters_free(filters_ptr, allocator); (*coder).block_options.filters = core::ptr::null_mut(); if ret_0 != LZMA_OK { return ret_0; @@ -356,7 +332,7 @@ unsafe extern "C" fn stream_decoder_memconfig( } LZMA_OK } -pub unsafe extern "C" fn lzma_stream_decoder_init( +pub(crate) unsafe extern "C" fn lzma_stream_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, memlimit: u64, diff --git a/liblzma-rs/src/common/stream_decoder_mt.rs b/xz/src/common/stream_decoder_mt.rs similarity index 99% rename from liblzma-rs/src/common/stream_decoder_mt.rs rename to xz/src/common/stream_decoder_mt.rs index 85efd24b..75cbfa8c 100644 --- a/liblzma-rs/src/common/stream_decoder_mt.rs +++ b/xz/src/common/stream_decoder_mt.rs @@ -566,13 +566,13 @@ unsafe fn decode_block_header( (*coder).block_options.ignore_check = (*coder).ignore_check as lzma_bool; LZMA_STREAM_END } -extern "C" fn comp_blk_size(coder: *const lzma_stream_coder) -> size_t { +fn comp_blk_size(coder: *const lzma_stream_coder) -> size_t { unsafe { (vli_ceil4((*coder).block_options.compressed_size) + lzma_check_size((*coder).stream_flags.check) as lzma_vli) as size_t } } -extern "C" fn is_direct_mode_needed(size: lzma_vli) -> bool { +fn is_direct_mode_needed(size: lzma_vli) -> bool { size == LZMA_VLI_UNKNOWN || size > SIZE_MAX.wrapping_div(3 as c_ulong) as lzma_vli } unsafe fn stream_decoder_reset( diff --git a/liblzma-rs/src/common/stream_encoder.rs b/xz/src/common/stream_encoder.rs similarity index 90% rename from liblzma-rs/src/common/stream_encoder.rs rename to xz/src/common/stream_encoder.rs index 42e03b76..b5c443ab 100644 --- a/liblzma-rs/src/common/stream_encoder.rs +++ b/xz/src/common/stream_encoder.rs @@ -1,4 +1,5 @@ use crate::types::*; +use core::mem::MaybeUninit; #[derive(Copy, Clone)] #[repr(C)] pub struct lzma_stream_coder { @@ -156,27 +157,13 @@ unsafe extern "C" fn stream_encode( if ret_0 != LZMA_STREAM_END { return ret_0; } - let stream_flags: lzma_stream_flags = lzma_stream_flags { - version: 0, - backward_size: lzma_index_size((*coder).index), - check: (*coder).block_options.check, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_bool1: 0, - reserved_bool2: 0, - reserved_bool3: 0, - reserved_bool4: 0, - reserved_bool5: 0, - reserved_bool6: 0, - reserved_bool7: 0, - reserved_bool8: 0, - reserved_int1: 0, - reserved_int2: 0, - }; + let mut stream_flags = MaybeUninit::::uninit(); + let stream_flags = stream_flags.as_mut_ptr(); + (*stream_flags).version = 0; + (*stream_flags).backward_size = lzma_index_size((*coder).index); + (*stream_flags).check = (*coder).block_options.check; if lzma_stream_footer_encode( - ::core::ptr::addr_of!(stream_flags), + stream_flags, ::core::ptr::addr_of_mut!((*coder).buffer) as *mut u8, ) != LZMA_OK { @@ -385,27 +372,12 @@ unsafe extern "C" fn stream_encoder_init( if (*coder).index.is_null() { return LZMA_MEM_ERROR; } - let mut stream_flags: lzma_stream_flags = lzma_stream_flags { - version: 0, - backward_size: 0, - check: check, - reserved_enum1: LZMA_RESERVED_ENUM, - reserved_enum2: LZMA_RESERVED_ENUM, - reserved_enum3: LZMA_RESERVED_ENUM, - reserved_enum4: LZMA_RESERVED_ENUM, - reserved_bool1: 0, - reserved_bool2: 0, - reserved_bool3: 0, - reserved_bool4: 0, - reserved_bool5: 0, - reserved_bool6: 0, - reserved_bool7: 0, - reserved_bool8: 0, - reserved_int1: 0, - reserved_int2: 0, - }; + let mut stream_flags = MaybeUninit::::uninit(); + let stream_flags = stream_flags.as_mut_ptr(); + (*stream_flags).version = 0; + (*stream_flags).check = check; let ret_: lzma_ret = lzma_stream_header_encode( - ::core::ptr::addr_of_mut!(stream_flags), + stream_flags, ::core::ptr::addr_of_mut!((*coder).buffer) as *mut u8, ); if ret_ != LZMA_OK { diff --git a/liblzma-rs/src/common/stream_encoder_mt.rs b/xz/src/common/stream_encoder_mt.rs similarity index 100% rename from liblzma-rs/src/common/stream_encoder_mt.rs rename to xz/src/common/stream_encoder_mt.rs diff --git a/liblzma-rs/src/common/stream_flags_common.rs b/xz/src/common/stream_flags_common.rs similarity index 100% rename from liblzma-rs/src/common/stream_flags_common.rs rename to xz/src/common/stream_flags_common.rs diff --git a/liblzma-rs/src/common/stream_flags_decoder.rs b/xz/src/common/stream_flags_decoder.rs similarity index 96% rename from liblzma-rs/src/common/stream_flags_decoder.rs rename to xz/src/common/stream_flags_decoder.rs index a43b6933..6a334de0 100644 --- a/liblzma-rs/src/common/stream_flags_decoder.rs +++ b/xz/src/common/stream_flags_decoder.rs @@ -1,6 +1,6 @@ use crate::common::stream_flags_common::{lzma_footer_magic, lzma_header_magic}; use crate::types::*; -extern "C" fn stream_flags_decode(options: *mut lzma_stream_flags, in_0: *const u8) -> bool { +fn stream_flags_decode(options: *mut lzma_stream_flags, in_0: *const u8) -> bool { return unsafe { if *in_0 != 0 || *in_0.offset(1) & 0xf0 != 0 { return true; diff --git a/liblzma-rs/src/common/stream_flags_encoder.rs b/xz/src/common/stream_flags_encoder.rs similarity index 95% rename from liblzma-rs/src/common/stream_flags_encoder.rs rename to xz/src/common/stream_flags_encoder.rs index c9695e31..f5655d8f 100644 --- a/liblzma-rs/src/common/stream_flags_encoder.rs +++ b/xz/src/common/stream_flags_encoder.rs @@ -1,6 +1,6 @@ use crate::common::stream_flags_common::{lzma_footer_magic, lzma_header_magic}; use crate::types::*; -extern "C" fn stream_flags_encode(options: *const lzma_stream_flags, out: *mut u8) -> bool { +fn stream_flags_encode(options: *const lzma_stream_flags, out: *mut u8) -> bool { return unsafe { if (*options).check > LZMA_CHECK_ID_MAX { return true; diff --git a/liblzma-rs/src/common/stream_mt.rs b/xz/src/common/stream_mt.rs similarity index 100% rename from liblzma-rs/src/common/stream_mt.rs rename to xz/src/common/stream_mt.rs diff --git a/liblzma-rs/src/common/string_conversion.rs b/xz/src/common/string_conversion.rs similarity index 99% rename from liblzma-rs/src/common/string_conversion.rs rename to xz/src/common/string_conversion.rs index b78093f9..c4897584 100644 --- a/liblzma-rs/src/common/string_conversion.rs +++ b/xz/src/common/string_conversion.rs @@ -896,12 +896,8 @@ unsafe fn str_to_filters( } _ => {} } - loop { - let old_i = i_0; + while i_0 > 0 { i_0 -= 1; - if old_i == 0 { - break; - } lzma_free(temp_filters[i_0 as usize].options, allocator); } errmsg diff --git a/liblzma-rs/src/common/vli_decoder.rs b/xz/src/common/vli_decoder.rs similarity index 100% rename from liblzma-rs/src/common/vli_decoder.rs rename to xz/src/common/vli_decoder.rs diff --git a/liblzma-rs/src/common/vli_encoder.rs b/xz/src/common/vli_encoder.rs similarity index 100% rename from liblzma-rs/src/common/vli_encoder.rs rename to xz/src/common/vli_encoder.rs diff --git a/liblzma-rs/src/common/vli_size.rs b/xz/src/common/vli_size.rs similarity index 100% rename from liblzma-rs/src/common/vli_size.rs rename to xz/src/common/vli_size.rs diff --git a/liblzma-rs/src/delta/delta_common.rs b/xz/src/delta/delta_common.rs similarity index 95% rename from liblzma-rs/src/delta/delta_common.rs rename to xz/src/delta/delta_common.rs index 50321d75..5c919724 100644 --- a/liblzma-rs/src/delta/delta_common.rs +++ b/xz/src/delta/delta_common.rs @@ -48,7 +48,7 @@ pub unsafe fn lzma_delta_coder_init( filters.offset(1), ) } -pub unsafe extern "C" fn lzma_delta_coder_memusage(options: *const c_void) -> u64 { +pub(crate) unsafe extern "C" fn lzma_delta_coder_memusage(options: *const c_void) -> u64 { let opt: *const lzma_options_delta = options as *const lzma_options_delta; if opt.is_null() || (*opt).type_0 != LZMA_DELTA_TYPE_BYTE diff --git a/liblzma-rs/src/delta/delta_decoder.rs b/xz/src/delta/delta_decoder.rs similarity index 80% rename from liblzma-rs/src/delta/delta_decoder.rs rename to xz/src/delta/delta_decoder.rs index eb6f25bf..c990de8e 100644 --- a/liblzma-rs/src/delta/delta_decoder.rs +++ b/xz/src/delta/delta_decoder.rs @@ -1,15 +1,19 @@ use crate::types::*; unsafe fn decode_buffer(coder: *mut lzma_delta_coder, buffer: *mut u8, size: size_t) { let distance: size_t = (*coder).distance; + let history = (*coder).history.as_mut_ptr(); + let mut pos = (*coder).pos; let mut i: size_t = 0; while i < size { - *buffer.offset(i as isize) = (*buffer.offset(i as isize)).wrapping_add( - (*coder).history[(distance.wrapping_add((*coder).pos as size_t) & 0xff) as usize], - ); - (*coder).history[((*coder).pos & 0xff) as usize] = *buffer.offset(i as isize); - (*coder).pos = (*coder).pos.wrapping_sub(1); + let byte_ptr = buffer.add(i); + let byte = (*byte_ptr) + .wrapping_add(*history.add((distance.wrapping_add(pos as size_t) & 0xff) as usize)); + *byte_ptr = byte; + *history.add((pos & 0xff) as usize) = byte; + pos = pos.wrapping_sub(1); i += 1; } + (*coder).pos = pos; } unsafe extern "C" fn delta_decode( coder_ptr: *mut c_void, @@ -42,7 +46,7 @@ unsafe extern "C" fn delta_decode( } ret } -pub unsafe extern "C" fn lzma_delta_decoder_init( +pub(crate) unsafe extern "C" fn lzma_delta_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -63,7 +67,7 @@ pub unsafe extern "C" fn lzma_delta_decoder_init( ); lzma_delta_coder_init(next, allocator, filters) } -pub unsafe extern "C" fn lzma_delta_props_decode( +pub(crate) unsafe extern "C" fn lzma_delta_props_decode( options: *mut *mut c_void, allocator: *const lzma_allocator, props: *const u8, diff --git a/liblzma-rs/src/delta/delta_encoder.rs b/xz/src/delta/delta_encoder.rs similarity index 96% rename from liblzma-rs/src/delta/delta_encoder.rs rename to xz/src/delta/delta_encoder.rs index a50640d1..786f5411 100644 --- a/liblzma-rs/src/delta/delta_encoder.rs +++ b/xz/src/delta/delta_encoder.rs @@ -100,7 +100,7 @@ unsafe extern "C" fn delta_encoder_update( reversed_filters.offset(1), ) } -pub unsafe extern "C" fn lzma_delta_encoder_init( +pub(crate) unsafe extern "C" fn lzma_delta_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -130,7 +130,10 @@ pub unsafe extern "C" fn lzma_delta_encoder_init( ); lzma_delta_coder_init(next, allocator, filters) } -pub unsafe extern "C" fn lzma_delta_props_encode(options: *const c_void, out: *mut u8) -> lzma_ret { +pub(crate) unsafe extern "C" fn lzma_delta_props_encode( + options: *const c_void, + out: *mut u8, +) -> lzma_ret { if lzma_delta_coder_memusage(options) == UINT64_MAX { return LZMA_PROG_ERROR; } diff --git a/liblzma-rs/src/delta/mod.rs b/xz/src/delta/mod.rs similarity index 100% rename from liblzma-rs/src/delta/mod.rs rename to xz/src/delta/mod.rs diff --git a/liblzma-rs/src/lib.rs b/xz/src/lib.rs similarity index 100% rename from liblzma-rs/src/lib.rs rename to xz/src/lib.rs diff --git a/liblzma-rs/src/lz/lz_decoder.rs b/xz/src/lz/lz_decoder.rs similarity index 100% rename from liblzma-rs/src/lz/lz_decoder.rs rename to xz/src/lz/lz_decoder.rs diff --git a/liblzma-rs/src/lz/lz_encoder.rs b/xz/src/lz/lz_encoder.rs similarity index 100% rename from liblzma-rs/src/lz/lz_encoder.rs rename to xz/src/lz/lz_encoder.rs diff --git a/liblzma-rs/src/lz/lz_encoder_mf.rs b/xz/src/lz/lz_encoder_mf.rs similarity index 90% rename from liblzma-rs/src/lz/lz_encoder_mf.rs rename to xz/src/lz/lz_encoder_mf.rs index 66c89056..3e1e6e84 100644 --- a/liblzma-rs/src/lz/lz_encoder_mf.rs +++ b/xz/src/lz/lz_encoder_mf.rs @@ -123,7 +123,10 @@ unsafe fn hc_find_func( } } #[inline] -pub unsafe extern "C" fn lzma_mf_hc3_find(mf: *mut lzma_mf, matches: *mut lzma_match) -> u32 { +pub(crate) unsafe extern "C" fn lzma_mf_hc3_find( + mf: *mut lzma_mf, + matches: *mut lzma_match, +) -> u32 { let mut len_limit: u32 = mf_avail(mf); if (*mf).nice_len <= len_limit { len_limit = (*mf).nice_len; @@ -174,7 +177,7 @@ pub unsafe extern "C" fn lzma_mf_hc3_find(mf: *mut lzma_mf, matches: *mut lzma_m matches_count } #[inline] -pub unsafe extern "C" fn lzma_mf_hc3_skip(mf: *mut lzma_mf, mut amount: u32) { +pub(crate) unsafe extern "C" fn lzma_mf_hc3_skip(mf: *mut lzma_mf, mut amount: u32) { loop { if mf_avail(mf) < 3 { move_pending(mf); @@ -201,7 +204,10 @@ pub unsafe extern "C" fn lzma_mf_hc3_skip(mf: *mut lzma_mf, mut amount: u32) { } } #[inline] -pub unsafe extern "C" fn lzma_mf_hc4_find(mf: *mut lzma_mf, matches: *mut lzma_match) -> u32 { +pub(crate) unsafe extern "C" fn lzma_mf_hc4_find( + mf: *mut lzma_mf, + matches: *mut lzma_match, +) -> u32 { let mut len_limit: u32 = mf_avail(mf); if (*mf).nice_len <= len_limit { len_limit = (*mf).nice_len; @@ -273,7 +279,7 @@ pub unsafe extern "C" fn lzma_mf_hc4_find(mf: *mut lzma_mf, matches: *mut lzma_m matches_count } #[inline] -pub unsafe extern "C" fn lzma_mf_hc4_skip(mf: *mut lzma_mf, mut amount: u32) { +pub(crate) unsafe extern "C" fn lzma_mf_hc4_skip(mf: *mut lzma_mf, mut amount: u32) { loop { if mf_avail(mf) < 4 { move_pending(mf); @@ -416,7 +422,10 @@ unsafe fn bt_skip_func( } } #[inline] -pub unsafe extern "C" fn lzma_mf_bt2_find(mf: *mut lzma_mf, matches: *mut lzma_match) -> u32 { +pub(crate) unsafe extern "C" fn lzma_mf_bt2_find( + mf: *mut lzma_mf, + matches: *mut lzma_match, +) -> u32 { let mut len_limit: u32 = mf_avail(mf); if (*mf).nice_len <= len_limit { len_limit = (*mf).nice_len; @@ -447,7 +456,7 @@ pub unsafe extern "C" fn lzma_mf_bt2_find(mf: *mut lzma_mf, matches: *mut lzma_m matches_count } #[inline] -pub unsafe extern "C" fn lzma_mf_bt2_skip(mf: *mut lzma_mf, mut amount: u32) { +pub(crate) unsafe extern "C" fn lzma_mf_bt2_skip(mf: *mut lzma_mf, mut amount: u32) { let mut current_block_8: u64; loop { let mut len_limit: u32 = mf_avail(mf); @@ -488,7 +497,10 @@ pub unsafe extern "C" fn lzma_mf_bt2_skip(mf: *mut lzma_mf, mut amount: u32) { } } #[inline] -pub unsafe extern "C" fn lzma_mf_bt3_find(mf: *mut lzma_mf, matches: *mut lzma_match) -> u32 { +pub(crate) unsafe extern "C" fn lzma_mf_bt3_find( + mf: *mut lzma_mf, + matches: *mut lzma_match, +) -> u32 { let mut len_limit: u32 = mf_avail(mf); if (*mf).nice_len <= len_limit { len_limit = (*mf).nice_len; @@ -548,7 +560,7 @@ pub unsafe extern "C" fn lzma_mf_bt3_find(mf: *mut lzma_mf, matches: *mut lzma_m matches_count } #[inline] -pub unsafe extern "C" fn lzma_mf_bt3_skip(mf: *mut lzma_mf, mut amount: u32) { +pub(crate) unsafe extern "C" fn lzma_mf_bt3_skip(mf: *mut lzma_mf, mut amount: u32) { let mut current_block_9: u64; loop { let mut len_limit: u32 = mf_avail(mf); @@ -596,7 +608,10 @@ pub unsafe extern "C" fn lzma_mf_bt3_skip(mf: *mut lzma_mf, mut amount: u32) { } } #[inline] -pub unsafe extern "C" fn lzma_mf_bt4_find(mf: *mut lzma_mf, matches: *mut lzma_match) -> u32 { +pub(crate) unsafe extern "C" fn lzma_mf_bt4_find( + mf: *mut lzma_mf, + matches: *mut lzma_match, +) -> u32 { let mut len_limit: u32 = mf_avail(mf); if (*mf).nice_len <= len_limit { len_limit = (*mf).nice_len; @@ -613,22 +628,27 @@ pub unsafe extern "C" fn lzma_mf_bt4_find(mf: *mut lzma_mf, matches: *mut lzma_m let hash_value: u32 = (temp ^ (*cur.offset(2) as u32) << 8 ^ lzma_crc32_table[0][*cur.offset(3) as usize] << 5) & (*mf).hash_mask; + let hash = (*mf).hash; + let son = (*mf).son; + let cyclic_pos = (*mf).cyclic_pos; + let cyclic_size = (*mf).cyclic_size; + let depth = (*mf).depth; let hash_3_index = FIX_3_HASH_SIZE as u32 + hash_3_value; let hash_4_index = FIX_4_HASH_SIZE as u32 + hash_value; - let mut delta2: u32 = pos - *(*mf).hash.offset(hash_2_value as isize); - let delta3: u32 = pos - *(*mf).hash.offset(hash_3_index as isize); - let cur_match: u32 = *(*mf).hash.offset(hash_4_index as isize); - *(*mf).hash.offset(hash_2_value as isize) = pos; - *(*mf).hash.offset(hash_3_index as isize) = pos; - *(*mf).hash.offset(hash_4_index as isize) = pos; + let mut delta2: u32 = pos - *hash.offset(hash_2_value as isize); + let delta3: u32 = pos - *hash.offset(hash_3_index as isize); + let cur_match: u32 = *hash.offset(hash_4_index as isize); + *hash.offset(hash_2_value as isize) = pos; + *hash.offset(hash_3_index as isize) = pos; + *hash.offset(hash_4_index as isize) = pos; let mut len_best: u32 = 1; - if delta2 < (*mf).cyclic_size && *cur.offset(-(delta2 as isize)) == *cur { + if delta2 < cyclic_size && *cur.offset(-(delta2 as isize)) == *cur { len_best = 2; (*matches).len = 2; (*matches).dist = delta2 - 1; matches_count = 1; } - if delta2 != delta3 && delta3 < (*mf).cyclic_size && *cur.offset(-(delta3 as isize)) == *cur { + if delta2 != delta3 && delta3 < cyclic_size && *cur.offset(-(delta3 as isize)) == *cur { len_best = 3; (*matches.offset(matches_count as isize)).dist = delta3 - 1; matches_count += 1; @@ -643,10 +663,10 @@ pub unsafe extern "C" fn lzma_mf_bt4_find(mf: *mut lzma_mf, matches: *mut lzma_m pos, cur, cur_match, - (*mf).depth, - (*mf).son, - (*mf).cyclic_pos, - (*mf).cyclic_size, + depth, + son, + cyclic_pos, + cyclic_size, ); move_pos(mf); return matches_count; @@ -660,10 +680,10 @@ pub unsafe extern "C" fn lzma_mf_bt4_find(mf: *mut lzma_mf, matches: *mut lzma_m pos, cur, cur_match, - (*mf).depth, - (*mf).son, - (*mf).cyclic_pos, - (*mf).cyclic_size, + depth, + son, + cyclic_pos, + cyclic_size, matches.offset(matches_count as isize), len_best, ) @@ -672,7 +692,7 @@ pub unsafe extern "C" fn lzma_mf_bt4_find(mf: *mut lzma_mf, matches: *mut lzma_m matches_count } #[inline] -pub unsafe extern "C" fn lzma_mf_bt4_skip(mf: *mut lzma_mf, mut amount: u32) { +pub(crate) unsafe extern "C" fn lzma_mf_bt4_skip(mf: *mut lzma_mf, mut amount: u32) { debug_assert!(amount > 0); loop { let mut len_limit: u32 = mf_avail(mf); @@ -696,23 +716,28 @@ pub unsafe extern "C" fn lzma_mf_bt4_skip(mf: *mut lzma_mf, mut amount: u32) { ^ (*cur.offset(2) as u32) << 8 ^ lzma_crc32_table[0][*cur.offset(3) as usize] << 5) & (*mf).hash_mask; + let hash = (*mf).hash; + let son = (*mf).son; + let cyclic_pos = (*mf).cyclic_pos; + let cyclic_size = (*mf).cyclic_size; + let depth = (*mf).depth; let hash_3_index = FIX_3_HASH_SIZE as u32 + hash_3_value; let hash_4_index = FIX_4_HASH_SIZE as u32 + hash_value; - let cur_match: u32 = *(*mf).hash.offset(hash_4_index as isize); + let cur_match: u32 = *hash.offset(hash_4_index as isize); - *(*mf).hash.offset(hash_2_value as isize) = pos; - *(*mf).hash.offset(hash_3_index as isize) = pos; - *(*mf).hash.offset(hash_4_index as isize) = pos; + *hash.offset(hash_2_value as isize) = pos; + *hash.offset(hash_3_index as isize) = pos; + *hash.offset(hash_4_index as isize) = pos; bt_skip_func( len_limit, pos, cur, cur_match, - (*mf).depth, - (*mf).son, - (*mf).cyclic_pos, - (*mf).cyclic_size, + depth, + son, + cyclic_pos, + cyclic_size, ); move_pos(mf); diff --git a/liblzma-rs/src/lz/mod.rs b/xz/src/lz/mod.rs similarity index 100% rename from liblzma-rs/src/lz/mod.rs rename to xz/src/lz/mod.rs diff --git a/liblzma-rs/src/lzma/fastpos_table.rs b/xz/src/lzma/fastpos_table.rs similarity index 100% rename from liblzma-rs/src/lzma/fastpos_table.rs rename to xz/src/lzma/fastpos_table.rs diff --git a/liblzma-rs/src/lzma/lzma2_decoder.rs b/xz/src/lzma/lzma2_decoder.rs similarity index 98% rename from liblzma-rs/src/lzma/lzma2_decoder.rs rename to xz/src/lzma/lzma2_decoder.rs index 8c2efd29..50f2ac80 100644 --- a/liblzma-rs/src/lzma/lzma2_decoder.rs +++ b/xz/src/lzma/lzma2_decoder.rs @@ -232,7 +232,7 @@ unsafe extern "C" fn lzma2_decoder_init( lz_options, ) } -pub unsafe extern "C" fn lzma_lzma2_decoder_init( +pub(crate) unsafe extern "C" fn lzma_lzma2_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -253,11 +253,11 @@ pub unsafe extern "C" fn lzma_lzma2_decoder_init( ), ) } -pub extern "C" fn lzma_lzma2_decoder_memusage(options: *const c_void) -> u64 { +pub(crate) extern "C" fn lzma_lzma2_decoder_memusage(options: *const c_void) -> u64 { (core::mem::size_of::() as u64) .wrapping_add(lzma_lzma_decoder_memusage_nocheck(options)) } -pub unsafe extern "C" fn lzma_lzma2_props_decode( +pub(crate) unsafe extern "C" fn lzma_lzma2_props_decode( options: *mut *mut c_void, allocator: *const lzma_allocator, props: *const u8, diff --git a/liblzma-rs/src/lzma/lzma2_encoder.rs b/xz/src/lzma/lzma2_encoder.rs similarity index 97% rename from liblzma-rs/src/lzma/lzma2_encoder.rs rename to xz/src/lzma/lzma2_encoder.rs index 5b64b54f..54b0ac3f 100644 --- a/liblzma-rs/src/lzma/lzma2_encoder.rs +++ b/xz/src/lzma/lzma2_encoder.rs @@ -331,7 +331,7 @@ unsafe extern "C" fn lzma2_encoder_init( } LZMA_OK } -pub unsafe extern "C" fn lzma_lzma2_encoder_init( +pub(crate) unsafe extern "C" fn lzma_lzma2_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -352,14 +352,17 @@ pub unsafe extern "C" fn lzma_lzma2_encoder_init( ), ) } -pub extern "C" fn lzma_lzma2_encoder_memusage(options: *const c_void) -> u64 { +pub(crate) extern "C" fn lzma_lzma2_encoder_memusage(options: *const c_void) -> u64 { let lzma_mem: u64 = lzma_lzma_encoder_memusage(options) as u64; if lzma_mem == UINT64_MAX { return UINT64_MAX; } (core::mem::size_of::() as u64) + lzma_mem } -pub unsafe extern "C" fn lzma_lzma2_props_encode(options: *const c_void, out: *mut u8) -> lzma_ret { +pub(crate) unsafe extern "C" fn lzma_lzma2_props_encode( + options: *const c_void, + out: *mut u8, +) -> lzma_ret { if options.is_null() { return LZMA_PROG_ERROR; } @@ -382,7 +385,7 @@ pub unsafe extern "C" fn lzma_lzma2_props_encode(options: *const c_void, out: *m } LZMA_OK } -pub unsafe extern "C" fn lzma_lzma2_block_size(options: *const c_void) -> u64 { +pub(crate) unsafe extern "C" fn lzma_lzma2_block_size(options: *const c_void) -> u64 { let opt: *const lzma_options_lzma = options as *const lzma_options_lzma; if (*opt).dict_size < LZMA_DICT_SIZE_MIN as u32 || (*opt).dict_size > (1u32 << 30) + (1 << 29) { return UINT64_MAX; diff --git a/liblzma-rs/src/lzma/lzma_decoder.rs b/xz/src/lzma/lzma_decoder.rs similarity index 98% rename from liblzma-rs/src/lzma/lzma_decoder.rs rename to xz/src/lzma/lzma_decoder.rs index 18ee3558..58b72a4c 100644 --- a/liblzma-rs/src/lzma/lzma_decoder.rs +++ b/xz/src/lzma/lzma_decoder.rs @@ -236,6 +236,10 @@ unsafe extern "C" fn lzma_decode( let mut limit: u32 = (*coder).limit; let mut offset: u32 = (*coder).offset; let mut len: u32 = (*coder).len; + let literal_probs: *mut probability = + ::core::ptr::addr_of_mut!((*coder).literal) as *mut probability; + let is_match_probs: *mut [probability; 16] = + ::core::ptr::addr_of_mut!((*coder).is_match) as *mut [probability; 16]; let literal_mask: u32 = (*coder).literal_mask; let literal_context_bits: u32 = (*coder).literal_context_bits; let mut pos_state: u32 = (dict.pos & pos_mask as size_t) as u32; @@ -903,29 +907,24 @@ unsafe extern "C" fn lzma_decode( rc_in_ptr = rc_in_ptr.offset(1); } } - rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) - .wrapping_mul((*coder).is_match[state as usize][pos_state as usize] as u32); + let is_match_prob = ::core::ptr::addr_of_mut!( + (*is_match_probs.add(state as usize))[pos_state as usize] + ); + rc_bound = + (rc.range >> RC_BIT_MODEL_TOTAL_BITS).wrapping_mul(*is_match_prob as u32); if rc.code < rc_bound { rc.range = rc_bound; - (*coder).is_match[state as usize][pos_state as usize] = ((*coder).is_match - [state as usize][pos_state as usize] - as u32) - .wrapping_add( - RC_BIT_MODEL_TOTAL.wrapping_sub( - (*coder).is_match[state as usize][pos_state as usize] as u32, - ) >> RC_MOVE_BITS, - ) - as probability - as probability; - probs = (::core::ptr::addr_of_mut!((*coder).literal) as *mut probability) - .offset( - (3_usize).wrapping_mul( - ((dict.pos << 8).wrapping_add( - dict_get0(::core::ptr::addr_of_mut!(dict)) as size_t, - ) & literal_mask as size_t) - << literal_context_bits, - ) as isize, - ); + *is_match_prob = (*is_match_prob as u32).wrapping_add( + RC_BIT_MODEL_TOTAL.wrapping_sub(*is_match_prob as u32) >> RC_MOVE_BITS, + ) as probability; + probs = literal_probs.offset( + (3_usize).wrapping_mul( + ((dict.pos << 8) + .wrapping_add(dict_get0(::core::ptr::addr_of_mut!(dict)) as size_t) + & literal_mask as size_t) + << literal_context_bits, + ) as isize, + ); symbol = 1; if state < LIT_STATES { state = if state <= STATE_SHORTREP_LIT_LIT { @@ -949,9 +948,7 @@ unsafe extern "C" fn lzma_decode( } else { rc.range = rc.range.wrapping_sub(rc_bound); rc.code = rc.code.wrapping_sub(rc_bound); - (*coder).is_match[state as usize][pos_state as usize] = (*coder).is_match - [state as usize][pos_state as usize] - - ((*coder).is_match[state as usize][pos_state as usize] >> RC_MOVE_BITS); + *is_match_prob = *is_match_prob - (*is_match_prob >> RC_MOVE_BITS); current_block = 3469750012682708893; continue; } @@ -1107,29 +1104,24 @@ unsafe extern "C" fn lzma_decode( rc.code = rc.code << RC_SHIFT_BITS | *rc_in_ptr as u32; rc_in_ptr = rc_in_ptr.offset(1); } - rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) - .wrapping_mul((*coder).is_match[state as usize][pos_state as usize] as u32); + let is_match_prob = ::core::ptr::addr_of_mut!( + (*is_match_probs.add(state as usize))[pos_state as usize] + ); + rc_bound = + (rc.range >> RC_BIT_MODEL_TOTAL_BITS).wrapping_mul(*is_match_prob as u32); if rc.code < rc_bound { rc.range = rc_bound; - (*coder).is_match[state as usize][pos_state as usize] = ((*coder).is_match - [state as usize][pos_state as usize] - as u32) - .wrapping_add( - RC_BIT_MODEL_TOTAL.wrapping_sub( - (*coder).is_match[state as usize][pos_state as usize] as u32, - ) >> RC_MOVE_BITS, - ) - as probability - as probability; - probs = (::core::ptr::addr_of_mut!((*coder).literal) as *mut probability) - .offset( - (3_usize).wrapping_mul( - ((dict.pos << 8).wrapping_add( - dict_get0(::core::ptr::addr_of_mut!(dict)) as size_t, - ) & literal_mask as size_t) - << literal_context_bits, - ) as isize, - ); + *is_match_prob = (*is_match_prob as u32).wrapping_add( + RC_BIT_MODEL_TOTAL.wrapping_sub(*is_match_prob as u32) >> RC_MOVE_BITS, + ) as probability; + probs = literal_probs.offset( + (3_usize).wrapping_mul( + ((dict.pos << 8) + .wrapping_add(dict_get0(::core::ptr::addr_of_mut!(dict)) as size_t) + & literal_mask as size_t) + << literal_context_bits, + ) as isize, + ); if state < LIT_STATES { state = if state <= STATE_SHORTREP_LIT_LIT { STATE_LIT_LIT @@ -1562,9 +1554,7 @@ unsafe extern "C" fn lzma_decode( } else { rc.range = rc.range.wrapping_sub(rc_bound); rc.code = rc.code.wrapping_sub(rc_bound); - (*coder).is_match[state as usize][pos_state as usize] = (*coder).is_match - [state as usize][pos_state as usize] - - ((*coder).is_match[state as usize][pos_state as usize] >> RC_MOVE_BITS); + *is_match_prob = *is_match_prob - (*is_match_prob >> RC_MOVE_BITS); if rc.range < RC_TOP_VALUE as u32 { rc.range <<= RC_SHIFT_BITS; rc.code = rc.code << RC_SHIFT_BITS | *rc_in_ptr as u32; @@ -3386,7 +3376,7 @@ unsafe extern "C" fn lzma_decoder_init( lzma_decoder_uncompressed((*lz).coder, uncomp_size, allow_eopm); LZMA_OK } -pub unsafe extern "C" fn lzma_lzma_decoder_init( +pub(crate) unsafe extern "C" fn lzma_lzma_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -3417,20 +3407,20 @@ pub unsafe fn lzma_lzma_lclppb_decode(options: *mut lzma_options_lzma, mut byte: (*options).lc = (byte as u32).wrapping_sub((*options).lp.wrapping_mul(9)); (*options).lc.wrapping_add((*options).lp) > LZMA_LCLP_MAX } -pub extern "C" fn lzma_lzma_decoder_memusage_nocheck(options: *const c_void) -> u64 { +pub(crate) extern "C" fn lzma_lzma_decoder_memusage_nocheck(options: *const c_void) -> u64 { return unsafe { let opt: *const lzma_options_lzma = options as *const lzma_options_lzma; (core::mem::size_of::() as u64) .wrapping_add(lzma_lz_decoder_memusage((*opt).dict_size as size_t)) }; } -pub extern "C" fn lzma_lzma_decoder_memusage(options: *const c_void) -> u64 { +pub(crate) extern "C" fn lzma_lzma_decoder_memusage(options: *const c_void) -> u64 { if !unsafe { is_lclppb_valid(options as *const lzma_options_lzma) } { return UINT64_MAX; } lzma_lzma_decoder_memusage_nocheck(options) } -pub unsafe extern "C" fn lzma_lzma_props_decode( +pub(crate) unsafe extern "C" fn lzma_lzma_props_decode( options: *mut *mut c_void, allocator: *const lzma_allocator, props: *const u8, diff --git a/liblzma-rs/src/lzma/lzma_encoder.rs b/xz/src/lzma/lzma_encoder.rs similarity index 90% rename from liblzma-rs/src/lzma/lzma_encoder.rs rename to xz/src/lzma/lzma_encoder.rs index 43588b40..dfa96664 100644 --- a/liblzma-rs/src/lzma/lzma_encoder.rs +++ b/xz/src/lzma/lzma_encoder.rs @@ -40,7 +40,7 @@ unsafe fn coder_rep_slot_mut(coder: *mut lzma_lzma1_encoder, index: usize) -> *m debug_assert!(index < REPS as usize); (::core::ptr::addr_of_mut!((*coder).reps) as *mut u32).add(index) } -#[inline] +#[inline(always)] unsafe fn rc_bittree( rc: *mut lzma_range_encoder, probs: *mut probability, @@ -62,7 +62,7 @@ unsafe fn rc_bittree( } } } -#[inline] +#[inline(always)] unsafe fn rc_bittree_reverse( rc: *mut lzma_range_encoder, probs: *mut probability, @@ -85,7 +85,7 @@ unsafe fn rc_bittree_reverse( } } } -#[inline] +#[inline(always)] unsafe fn rc_direct(rc: *mut lzma_range_encoder, value: u32, mut bit_count: u32) { loop { bit_count -= 1; @@ -97,7 +97,7 @@ unsafe fn rc_direct(rc: *mut lzma_range_encoder, value: u32, mut bit_count: u32) } } } -#[inline] +#[inline(always)] unsafe fn rc_flush(rc: *mut lzma_range_encoder) { let mut i: size_t = 0; while i < 5 { @@ -106,31 +106,34 @@ unsafe fn rc_flush(rc: *mut lzma_range_encoder) { i += 1; } } -#[inline] -unsafe fn rc_shift_low( - rc: *mut lzma_range_encoder, +#[inline(always)] +unsafe fn rc_shift_low_raw( + low: &mut u64, + cache_size: &mut u64, + cache: &mut u8, + out_total: &mut u64, out: *mut u8, out_pos: *mut size_t, out_size: size_t, ) -> bool { - if ((*rc).low as u32) < 0xff000000 || ((*rc).low >> 32) as u32 != 0 { + if (*low as u32) < 0xff000000 || (*low >> 32) as u32 != 0 { loop { if *out_pos == out_size { return true; } - *out.offset(*out_pos as isize) = (*rc).cache.wrapping_add(((*rc).low >> 32) as u8); + *out.add(*out_pos) = cache.wrapping_add((*low >> 32) as u8); *out_pos += 1; - (*rc).out_total += 1; - (*rc).cache = 0xff; - (*rc).cache_size -= 1; - if (*rc).cache_size == 0 { + *out_total += 1; + *cache = 0xff; + *cache_size -= 1; + if *cache_size == 0 { break; } } - (*rc).cache = ((*rc).low >> 24 & 0xff as u64) as u8; + *cache = ((*low >> 24) & 0xff) as u8; } - (*rc).cache_size += 1; - (*rc).low = ((*rc).low & 0xffffff as u64) << RC_SHIFT_BITS; + *cache_size += 1; + *low = (*low & 0x00ff_ffff) << RC_SHIFT_BITS; false } #[inline] @@ -159,53 +162,92 @@ unsafe fn rc_shift_low_dummy( *low = (*low & 0xffffff as u64) << RC_SHIFT_BITS; false } -#[inline] +#[inline(always)] unsafe fn rc_encode( rc: *mut lzma_range_encoder, out: *mut u8, out_pos: *mut size_t, out_size: size_t, ) -> bool { - while (*rc).pos < (*rc).count { - if (*rc).range < RC_TOP_VALUE as u32 { - if rc_shift_low(rc, out, out_pos, out_size) { + let symbols = ::core::ptr::addr_of_mut!((*rc).symbols) as *mut rc_symbol; + let probs = ::core::ptr::addr_of_mut!((*rc).probs) as *mut *mut probability; + let mut low = (*rc).low; + let mut cache_size = (*rc).cache_size; + let mut range = (*rc).range; + let mut cache = (*rc).cache; + let mut out_total = (*rc).out_total; + let count = (*rc).count; + let mut pos = (*rc).pos; + + while pos < count { + if range < RC_TOP_VALUE as u32 { + if rc_shift_low_raw( + &mut low, + &mut cache_size, + &mut cache, + &mut out_total, + out, + out_pos, + out_size, + ) { + (*rc).low = low; + (*rc).cache_size = cache_size; + (*rc).range = range; + (*rc).cache = cache; + (*rc).out_total = out_total; + (*rc).pos = pos; return true; } - (*rc).range <<= RC_SHIFT_BITS; + range <<= RC_SHIFT_BITS; } - match *rc_symbol_slot_mut(rc, (*rc).pos) { + match *symbols.add(pos) { 0 => { - let mut prob: probability = **rc_prob_slot_mut(rc, (*rc).pos); - (*rc).range = ((*rc).range >> RC_BIT_MODEL_TOTAL_BITS).wrapping_mul(prob as u32); + let prob_ptr = *probs.add(pos); + let mut prob: probability = *prob_ptr; + range = (range >> RC_BIT_MODEL_TOTAL_BITS).wrapping_mul(prob as u32); prob = (prob as u32) .wrapping_add(RC_BIT_MODEL_TOTAL.wrapping_sub(prob as u32) >> RC_MOVE_BITS) as probability; - **rc_prob_slot_mut(rc, (*rc).pos) = prob; + *prob_ptr = prob; } 1 => { - let mut prob_0: probability = **rc_prob_slot_mut(rc, (*rc).pos); - let bound: u32 = - (prob_0 as u32).wrapping_mul((*rc).range >> RC_BIT_MODEL_TOTAL_BITS); - (*rc).low = (*rc).low.wrapping_add(bound as u64); - (*rc).range = (*rc).range.wrapping_sub(bound); + let prob_ptr = *probs.add(pos); + let mut prob_0: probability = *prob_ptr; + let bound: u32 = (prob_0 as u32).wrapping_mul(range >> RC_BIT_MODEL_TOTAL_BITS); + low = low.wrapping_add(bound as u64); + range = range.wrapping_sub(bound); prob_0 -= prob_0 >> RC_MOVE_BITS; - **rc_prob_slot_mut(rc, (*rc).pos) = prob_0; + *prob_ptr = prob_0; } 2 => { - (*rc).range >>= 1; + range >>= 1; } 3 => { - (*rc).range >>= 1; - (*rc).low = (*rc).low.wrapping_add((*rc).range as u64); + range >>= 1; + low = low.wrapping_add(range as u64); } 4 => { - (*rc).range = UINT32_MAX; + range = UINT32_MAX; loop { - if rc_shift_low(rc, out, out_pos, out_size) { + if rc_shift_low_raw( + &mut low, + &mut cache_size, + &mut cache, + &mut out_total, + out, + out_pos, + out_size, + ) { + (*rc).low = low; + (*rc).cache_size = cache_size; + (*rc).range = range; + (*rc).cache = cache; + (*rc).out_total = out_total; + (*rc).pos = pos; return true; } - (*rc).pos += 1; - if (*rc).pos >= (*rc).count { + pos += 1; + if pos >= count { break; } } @@ -214,8 +256,13 @@ unsafe fn rc_encode( } _ => {} } - (*rc).pos += 1; + pos += 1; } + (*rc).low = low; + (*rc).cache_size = cache_size; + (*rc).range = range; + (*rc).cache = cache; + (*rc).out_total = out_total; (*rc).count = 0; (*rc).pos = 0; false @@ -287,7 +334,7 @@ unsafe fn rc_pending(rc: *const lzma_range_encoder) -> u64 { } pub const LEN_SYMBOLS: u32 = LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS; pub const MATCH_LEN_MAX: u32 = MATCH_LEN_MIN + LEN_SYMBOLS - 1; -#[inline] +#[inline(always)] unsafe fn literal_matched( rc: *mut lzma_range_encoder, subcoder: *mut probability, @@ -313,7 +360,7 @@ unsafe fn literal_matched( } } } -#[inline] +#[inline(always)] unsafe fn literal(coder: *mut lzma_lzma1_encoder, mf: *mut lzma_mf, position: u32) { let cur_byte: u8 = *(*mf) .buffer @@ -418,7 +465,7 @@ unsafe fn length_update_prices(lc: *mut lzma_length_encoder, pos_state: u32) { i += 1; } } -#[inline] +#[inline(always)] unsafe fn length( rc: *mut lzma_range_encoder, lc: *mut lzma_length_encoder, @@ -454,7 +501,7 @@ unsafe fn length( } } } -#[inline] +#[inline(always)] unsafe fn match_0(coder: *mut lzma_lzma1_encoder, pos_state: u32, distance: u32, len: u32) { (*coder).state = (if ((*coder).state as u32) < LIT_STATES { STATE_LIT_MATCH @@ -517,7 +564,7 @@ unsafe fn match_0(coder: *mut lzma_lzma1_encoder, pos_state: u32, distance: u32, *coder_rep_slot_mut(coder, 0) = distance; (*coder).match_price_count += 1; } -#[inline] +#[inline(always)] unsafe fn rep_match(coder: *mut lzma_lzma1_encoder, pos_state: u32, rep: u32, len: u32) { if rep == 0 { rc_bit( @@ -591,6 +638,7 @@ unsafe fn rep_match(coder: *mut lzma_lzma1_encoder, pos_state: u32, rep: u32, le }) as lzma_lzma_state; }; } +#[inline(always)] unsafe fn encode_symbol( coder: *mut lzma_lzma1_encoder, mf: *mut lzma_mf, @@ -796,7 +844,7 @@ unsafe extern "C" fn lzma_lzma_set_out_limit( (*coder).use_eopm = false; LZMA_OK } -extern "C" fn is_options_valid(options: *const lzma_options_lzma) -> bool { +fn is_options_valid(options: *const lzma_options_lzma) -> bool { unsafe { is_lclppb_valid(options) && (*options).nice_len >= MATCH_LEN_MIN @@ -804,7 +852,7 @@ extern "C" fn is_options_valid(options: *const lzma_options_lzma) -> bool { && ((*options).mode == LZMA_MODE_FAST || (*options).mode == LZMA_MODE_NORMAL) } } -extern "C" fn set_lz_options(lz_options: *mut lzma_lz_options, options: *const lzma_options_lzma) { +fn set_lz_options(lz_options: *mut lzma_lz_options, options: *const lzma_options_lzma) { unsafe { (*lz_options).before_size = OPTS as size_t; (*lz_options).dict_size = (*options).dict_size as size_t; @@ -1015,7 +1063,7 @@ unsafe extern "C" fn lzma_encoder_init( lz_options, ) } -pub unsafe extern "C" fn lzma_lzma_encoder_init( +pub(crate) unsafe extern "C" fn lzma_lzma_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -1036,7 +1084,7 @@ pub unsafe extern "C" fn lzma_lzma_encoder_init( ), ) } -pub extern "C" fn lzma_lzma_encoder_memusage(options: *const c_void) -> u64 { +pub(crate) extern "C" fn lzma_lzma_encoder_memusage(options: *const c_void) -> u64 { if !is_options_valid(options as *const lzma_options_lzma) { return UINT64_MAX; } @@ -1068,7 +1116,10 @@ pub unsafe fn lzma_lzma_lclppb_encode(options: *const lzma_options_lzma, byte: * *byte = (((*options).pb * 5 + (*options).lp) * 9 + (*options).lc) as u8; false } -pub unsafe extern "C" fn lzma_lzma_props_encode(options: *const c_void, out: *mut u8) -> lzma_ret { +pub(crate) unsafe extern "C" fn lzma_lzma_props_encode( + options: *const c_void, + out: *mut u8, +) -> lzma_ret { if options.is_null() { return LZMA_PROG_ERROR; } diff --git a/liblzma-rs/src/lzma/lzma_encoder_optimum_fast.rs b/xz/src/lzma/lzma_encoder_optimum_fast.rs similarity index 100% rename from liblzma-rs/src/lzma/lzma_encoder_optimum_fast.rs rename to xz/src/lzma/lzma_encoder_optimum_fast.rs diff --git a/liblzma-rs/src/lzma/lzma_encoder_optimum_normal.rs b/xz/src/lzma/lzma_encoder_optimum_normal.rs similarity index 100% rename from liblzma-rs/src/lzma/lzma_encoder_optimum_normal.rs rename to xz/src/lzma/lzma_encoder_optimum_normal.rs diff --git a/liblzma-rs/src/lzma/lzma_encoder_presets.rs b/xz/src/lzma/lzma_encoder_presets.rs similarity index 100% rename from liblzma-rs/src/lzma/lzma_encoder_presets.rs rename to xz/src/lzma/lzma_encoder_presets.rs diff --git a/liblzma-rs/src/lzma/mod.rs b/xz/src/lzma/mod.rs similarity index 100% rename from liblzma-rs/src/lzma/mod.rs rename to xz/src/lzma/mod.rs diff --git a/liblzma-rs/src/rangecoder/mod.rs b/xz/src/rangecoder/mod.rs similarity index 100% rename from liblzma-rs/src/rangecoder/mod.rs rename to xz/src/rangecoder/mod.rs diff --git a/liblzma-rs/src/rangecoder/price_table.rs b/xz/src/rangecoder/price_table.rs similarity index 100% rename from liblzma-rs/src/rangecoder/price_table.rs rename to xz/src/rangecoder/price_table.rs diff --git a/xz/src/simple/arm.rs b/xz/src/simple/arm.rs new file mode 100644 index 00000000..a63faab5 --- /dev/null +++ b/xz/src/simple/arm.rs @@ -0,0 +1,73 @@ +use crate::types::*; +fn arm_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + let size = buffer.len() & !3; + let mut i: size_t = 0; + while i < size { + if buffer[i + 3] == 0xeb { + let mut src: u32 = + (buffer[i + 2] as u32) << 16 | (buffer[i + 1] as u32) << 8 | buffer[i] as u32; + src <<= 2; + let dest = if is_encoder { + now_pos + .wrapping_add(i as u32) + .wrapping_add(8) + .wrapping_add(src) + } else { + src.wrapping_sub(now_pos.wrapping_add(i as u32).wrapping_add(8)) + }; + let dest = dest >> 2; + buffer[i + 2] = (dest >> 16) as u8; + buffer[i + 1] = (dest >> 8) as u8; + buffer[i] = dest as u8; + } + i += 4; + } + i +} +unsafe extern "C" fn arm_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + arm_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn arm_coder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, + is_encoder: bool, +) -> lzma_ret { + lzma_simple_coder_init( + next, + allocator, + filters, + Some(arm_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t), + 0, + 4, + 4, + is_encoder, + ) +} +pub(crate) unsafe extern "C" fn lzma_simple_arm_encoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + arm_coder_init(next, allocator, filters, true) +} +pub(crate) unsafe extern "C" fn lzma_simple_arm_decoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + arm_coder_init(next, allocator, filters, false) +} diff --git a/liblzma-rs/src/simple/arm64.rs b/xz/src/simple/arm64.rs similarity index 52% rename from liblzma-rs/src/simple/arm64.rs rename to xz/src/simple/arm64.rs index f9f5c934..56db80b0 100644 --- a/liblzma-rs/src/simple/arm64.rs +++ b/xz/src/simple/arm64.rs @@ -1,17 +1,10 @@ use crate::types::*; -unsafe extern "C" fn arm64_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - size &= !(3); +fn arm64_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + let size = buffer.len() & !3; let mut i: size_t = 0; - i = 0; while i < size { let mut pc: u32 = now_pos.wrapping_add(i as u32); - let mut instr: u32 = read32le(buffer.offset(i as isize)); + let mut instr: u32 = read32le(buffer.as_mut_ptr().wrapping_add(i)); if instr >> 26 == 0x25 { let src: u32 = instr; instr = 0x94000000; @@ -20,49 +13,60 @@ unsafe extern "C" fn arm64_code( pc = 0u32.wrapping_sub(pc); } instr |= src.wrapping_add(pc) & 0x3ffffff; - write32le(buffer.offset(i as isize), instr); + write32le(buffer.as_mut_ptr().wrapping_add(i), instr); } else if instr & 0x9f000000 == 0x90000000 { - let src_0: u32 = instr >> 29 & 3 | instr >> 3 & 0x1ffffc; - if src_0.wrapping_add(0x20000) & 0x1c0000 == 0 { - instr = (instr & 0x9000001f) as u32; + let src: u32 = instr >> 29 & 3 | instr >> 3 & 0x1ffffc; + if src.wrapping_add(0x20000) & 0x1c0000 == 0 { + instr &= 0x9000001f; pc >>= 12; if !is_encoder { pc = 0u32.wrapping_sub(pc); } - let dest: u32 = src_0.wrapping_add(pc); + let dest: u32 = src.wrapping_add(pc); instr |= (dest & 3) << 29; instr |= (dest & 0x3fffc) << 3; - instr = (instr | (0u32.wrapping_sub(dest & 0x20000) & 0xe00000)) as u32; - write32le(buffer.offset(i as isize), instr); + instr |= 0u32.wrapping_sub(dest & 0x20000) & 0xe00000; + write32le(buffer.as_mut_ptr().wrapping_add(i), instr); } } i += 4; } i } -extern "C" fn arm64_coder_init( +unsafe extern "C" fn arm64_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + arm64_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn arm64_coder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, is_encoder: bool, ) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - arm64_code - as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 4, - 4, - is_encoder, - ) - } + lzma_simple_coder_init( + next, + allocator, + filters, + Some(arm64_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t), + 0, + 4, + 4, + is_encoder, + ) } -pub unsafe extern "C" fn lzma_simple_arm64_encoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_arm64_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -71,9 +75,16 @@ pub unsafe extern "C" fn lzma_simple_arm64_encoder_init( } pub unsafe fn lzma_bcj_arm64_encode(mut start_offset: u32, buf: *mut u8, size: size_t) -> size_t { start_offset = (start_offset & !3u32) as u32; - arm64_code(core::ptr::null_mut(), start_offset, true, buf, size) + if size == 0 { + return 0; + } + arm64_code_impl( + start_offset, + true, + core::slice::from_raw_parts_mut(buf, size), + ) } -pub unsafe extern "C" fn lzma_simple_arm64_decoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_arm64_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -82,5 +93,12 @@ pub unsafe extern "C" fn lzma_simple_arm64_decoder_init( } pub unsafe fn lzma_bcj_arm64_decode(mut start_offset: u32, buf: *mut u8, size: size_t) -> size_t { start_offset = (start_offset & !3u32) as u32; - arm64_code(core::ptr::null_mut(), start_offset, false, buf, size) + if size == 0 { + return 0; + } + arm64_code_impl( + start_offset, + false, + core::slice::from_raw_parts_mut(buf, size), + ) } diff --git a/xz/src/simple/armthumb.rs b/xz/src/simple/armthumb.rs new file mode 100644 index 00000000..01b01696 --- /dev/null +++ b/xz/src/simple/armthumb.rs @@ -0,0 +1,83 @@ +use crate::types::*; +fn armthumb_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + if buffer.len() < 4 { + return 0; + } + let size = buffer.len() - 4; + let mut i: size_t = 0; + while i <= size { + if buffer[i + 1] & 0xf8 == 0xf0 && buffer[i + 3] & 0xf8 == 0xf8 { + let mut src: u32 = (buffer[i + 1] as u32 & 7) << 19 + | (buffer[i] as u32) << 11 + | (buffer[i + 3] as u32 & 7) << 8 + | buffer[i + 2] as u32; + src <<= 1; + let dest = if is_encoder { + now_pos + .wrapping_add(i as u32) + .wrapping_add(4) + .wrapping_add(src) + } else { + src.wrapping_sub(now_pos.wrapping_add(i as u32).wrapping_add(4)) + }; + let dest = dest >> 1; + buffer[i + 1] = (0xf0 | dest >> 19 & 0x7) as u8; + buffer[i] = (dest >> 11) as u8; + buffer[i + 3] = (0xf8 | dest >> 8 & 0x7) as u8; + buffer[i + 2] = dest as u8; + i += 2; + } + i += 2; + } + i +} +unsafe extern "C" fn armthumb_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + armthumb_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn armthumb_coder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, + is_encoder: bool, +) -> lzma_ret { + lzma_simple_coder_init( + next, + allocator, + filters, + Some( + armthumb_code + as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, + ), + 0, + 4, + 2, + is_encoder, + ) +} +pub(crate) unsafe extern "C" fn lzma_simple_armthumb_encoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + armthumb_coder_init(next, allocator, filters, true) +} +pub(crate) unsafe extern "C" fn lzma_simple_armthumb_decoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + armthumb_coder_init(next, allocator, filters, false) +} diff --git a/liblzma-rs/src/simple/ia64.rs b/xz/src/simple/ia64.rs similarity index 55% rename from liblzma-rs/src/simple/ia64.rs rename to xz/src/simple/ia64.rs index aa8a2dfa..90a4e723 100644 --- a/liblzma-rs/src/simple/ia64.rs +++ b/xz/src/simple/ia64.rs @@ -1,20 +1,13 @@ use crate::types::*; -unsafe extern "C" fn ia64_code( - _simple: *mut c_void, - now_pos: u32, - is_encoder: bool, - buffer: *mut u8, - mut size: size_t, -) -> size_t { - static mut BRANCH_TABLE: [u32; 32] = [ +fn ia64_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + const BRANCH_TABLE: [u32; 32] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0, ]; - size &= !(15); + let size = buffer.len() & !15; let mut i: size_t = 0; - i = 0; while i < size { - let instr_template: u32 = (*buffer.offset(i as isize) & 0x1f) as u32; + let instr_template: u32 = (buffer[i] & 0x1f) as u32; let mask: u32 = BRANCH_TABLE[instr_template as usize]; let mut bit_pos: u32 = 5; let mut slot: size_t = 0; @@ -25,31 +18,29 @@ unsafe extern "C" fn ia64_code( let mut instruction: u64 = 0; let mut j: size_t = 0; while j < 6 { - instruction += (*buffer.offset((i + j + byte_pos) as isize) as u64) << (8 * j); + instruction += (buffer[i + j + byte_pos] as u64) << (8 * j); j += 1; } let mut inst_norm: u64 = instruction >> bit_res; - if inst_norm >> 37 & 0xf as u64 == 0x5 as u64 && inst_norm >> 9 & 0x7 as u64 == 0 { - let mut src: u32 = (inst_norm >> 13 & 0xfffff as u64) as u32; + if inst_norm >> 37 & 0xf == 0x5 && inst_norm >> 9 & 0x7 == 0 { + let mut src: u32 = (inst_norm >> 13 & 0xfffff) as u32; src = (src as u64 | (inst_norm >> 36 & 1) << 20) as u32; src <<= 4; - let mut dest: u32 = 0; - if is_encoder { - dest = now_pos.wrapping_add(i as u32).wrapping_add(src); + let dest = if is_encoder { + now_pos.wrapping_add(i as u32).wrapping_add(src) } else { - dest = src.wrapping_sub(now_pos.wrapping_add(i as u32)); - } - dest >>= 4; - inst_norm &= !((0x8fffff as u64) << 13); + src.wrapping_sub(now_pos.wrapping_add(i as u32)) + }; + let dest = dest >> 4; + inst_norm &= !(0x8fffff_u64 << 13); inst_norm |= ((dest & 0xfffff) as u64) << 13; - inst_norm |= ((dest & 0x100000) as u64) << 36 - 20; + inst_norm |= ((dest & 0x100000) as u64) << 16; instruction &= ((1u32 << bit_res) - 1) as u64; instruction |= inst_norm << bit_res; - let mut j_0: size_t = 0; - while j_0 < 6 { - *buffer.offset((i + j_0 + byte_pos) as isize) = - (instruction >> (8 * j_0)) as u8; - j_0 += 1; + let mut j: size_t = 0; + while j < 6 { + buffer[i + j + byte_pos] = (instruction >> (8 * j)) as u8; + j += 1; } } } @@ -60,36 +51,47 @@ unsafe extern "C" fn ia64_code( } i } -extern "C" fn ia64_coder_init( +unsafe extern "C" fn ia64_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + ia64_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn ia64_coder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, is_encoder: bool, ) -> lzma_ret { - unsafe { - lzma_simple_coder_init( - next, - allocator, - filters, - Some( - ia64_code - as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - 0, - 16, - 16, - is_encoder, - ) - } + lzma_simple_coder_init( + next, + allocator, + filters, + Some(ia64_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t), + 0, + 16, + 16, + is_encoder, + ) } -pub unsafe extern "C" fn lzma_simple_ia64_encoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_ia64_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, ) -> lzma_ret { ia64_coder_init(next, allocator, filters, true) } -pub unsafe extern "C" fn lzma_simple_ia64_decoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_ia64_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, diff --git a/liblzma-rs/src/simple/mod.rs b/xz/src/simple/mod.rs similarity index 100% rename from liblzma-rs/src/simple/mod.rs rename to xz/src/simple/mod.rs diff --git a/xz/src/simple/powerpc.rs b/xz/src/simple/powerpc.rs new file mode 100644 index 00000000..31820413 --- /dev/null +++ b/xz/src/simple/powerpc.rs @@ -0,0 +1,74 @@ +use crate::types::*; +fn powerpc_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + let size = buffer.len() & !3; + let mut i: size_t = 0; + while i < size { + if buffer[i] >> 2 == 0x12 && buffer[i + 3] & 3 == 1 { + let src: u32 = (buffer[i] as u32 & 3) << 24 + | (buffer[i + 1] as u32) << 16 + | (buffer[i + 2] as u32) << 8 + | (buffer[i + 3] as u32 & !3); + let dest = if is_encoder { + now_pos.wrapping_add(i as u32).wrapping_add(src) + } else { + src.wrapping_sub(now_pos.wrapping_add(i as u32)) + }; + buffer[i] = (0x48 | dest >> 24 & 0x3) as u8; + buffer[i + 1] = (dest >> 16) as u8; + buffer[i + 2] = (dest >> 8) as u8; + buffer[i + 3] &= 0x3; + buffer[i + 3] = (buffer[i + 3] as u32 | dest) as u8; + } + i += 4; + } + i +} +unsafe extern "C" fn powerpc_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + powerpc_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn powerpc_coder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, + is_encoder: bool, +) -> lzma_ret { + lzma_simple_coder_init( + next, + allocator, + filters, + Some( + powerpc_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, + ), + 0, + 4, + 4, + is_encoder, + ) +} +pub(crate) unsafe extern "C" fn lzma_simple_powerpc_encoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + powerpc_coder_init(next, allocator, filters, true) +} +pub(crate) unsafe extern "C" fn lzma_simple_powerpc_decoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + powerpc_coder_init(next, allocator, filters, false) +} diff --git a/liblzma-rs/src/simple/riscv.rs b/xz/src/simple/riscv.rs similarity index 97% rename from liblzma-rs/src/simple/riscv.rs rename to xz/src/simple/riscv.rs index ccbacc7c..2ae98818 100644 --- a/liblzma-rs/src/simple/riscv.rs +++ b/xz/src/simple/riscv.rs @@ -1,6 +1,6 @@ use crate::types::*; #[inline] -extern "C" fn read32be(buf: *const u8) -> u32 { +fn read32be(buf: *const u8) -> u32 { return unsafe { let mut num: u32 = (*buf as u32) << 24; num |= (*buf.offset(1) as u32) << 16; @@ -10,7 +10,7 @@ extern "C" fn read32be(buf: *const u8) -> u32 { }; } #[inline] -extern "C" fn write32be(buf: *mut u8, num: u32) { +fn write32be(buf: *mut u8, num: u32) { unsafe { *buf = (num >> 24) as u8; *buf.offset(1) = (num >> 16) as u8; @@ -95,7 +95,7 @@ unsafe extern "C" fn riscv_encode( } i } -pub unsafe extern "C" fn lzma_simple_riscv_encoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_riscv_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -190,7 +190,7 @@ unsafe extern "C" fn riscv_decode( } i } -pub unsafe extern "C" fn lzma_simple_riscv_decoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_riscv_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, diff --git a/liblzma-rs/src/simple/simple_coder.rs b/xz/src/simple/simple_coder.rs similarity index 99% rename from liblzma-rs/src/simple/simple_coder.rs rename to xz/src/simple/simple_coder.rs index 2c8bc11e..267ec3c7 100644 --- a/liblzma-rs/src/simple/simple_coder.rs +++ b/xz/src/simple/simple_coder.rs @@ -1,4 +1,5 @@ use crate::types::*; + unsafe fn copy_or_code( coder: *mut lzma_simple_coder, allocator: *const lzma_allocator, diff --git a/liblzma-rs/src/simple/simple_decoder.rs b/xz/src/simple/simple_decoder.rs similarity index 92% rename from liblzma-rs/src/simple/simple_decoder.rs rename to xz/src/simple/simple_decoder.rs index 006ab061..d606346a 100644 --- a/liblzma-rs/src/simple/simple_decoder.rs +++ b/xz/src/simple/simple_decoder.rs @@ -1,5 +1,5 @@ use crate::types::*; -pub unsafe extern "C" fn lzma_simple_props_decode( +pub(crate) unsafe extern "C" fn lzma_simple_props_decode( options: *mut *mut c_void, allocator: *const lzma_allocator, props: *const u8, diff --git a/liblzma-rs/src/simple/simple_encoder.rs b/xz/src/simple/simple_encoder.rs similarity index 82% rename from liblzma-rs/src/simple/simple_encoder.rs rename to xz/src/simple/simple_encoder.rs index 4aca0cb1..2919eef1 100644 --- a/liblzma-rs/src/simple/simple_encoder.rs +++ b/xz/src/simple/simple_encoder.rs @@ -1,5 +1,5 @@ use crate::types::*; -pub unsafe extern "C" fn lzma_simple_props_size( +pub(crate) unsafe extern "C" fn lzma_simple_props_size( size: *mut u32, options: *const c_void, ) -> lzma_ret { @@ -11,7 +11,7 @@ pub unsafe extern "C" fn lzma_simple_props_size( }) as u32; LZMA_OK } -pub unsafe extern "C" fn lzma_simple_props_encode( +pub(crate) unsafe extern "C" fn lzma_simple_props_encode( options: *const c_void, out: *mut u8, ) -> lzma_ret { diff --git a/xz/src/simple/sparc.rs b/xz/src/simple/sparc.rs new file mode 100644 index 00000000..45fb6e40 --- /dev/null +++ b/xz/src/simple/sparc.rs @@ -0,0 +1,77 @@ +use crate::types::*; +fn sparc_code_impl(now_pos: u32, is_encoder: bool, buffer: &mut [u8]) -> size_t { + let size = buffer.len() & !3; + let mut i: size_t = 0; + while i < size { + if buffer[i] == 0x40 && buffer[i + 1] & 0xc0 == 0 + || buffer[i] == 0x7f && buffer[i + 1] & 0xc0 == 0xc0 + { + let mut src: u32 = (buffer[i] as u32) << 24 + | (buffer[i + 1] as u32) << 16 + | (buffer[i + 2] as u32) << 8 + | buffer[i + 3] as u32; + src <<= 2; + let dest = if is_encoder { + now_pos.wrapping_add(i as u32).wrapping_add(src) + } else { + src.wrapping_sub(now_pos.wrapping_add(i as u32)) + }; + let mut dest = dest >> 2; + dest = + 0u32.wrapping_sub(dest >> 22 & 1) << 22 & 0x3fffffff | dest & 0x3fffff | 0x40000000; + buffer[i] = (dest >> 24) as u8; + buffer[i + 1] = (dest >> 16) as u8; + buffer[i + 2] = (dest >> 8) as u8; + buffer[i + 3] = dest as u8; + } + i += 4; + } + i +} +unsafe extern "C" fn sparc_code( + _simple: *mut c_void, + now_pos: u32, + is_encoder: bool, + buffer: *mut u8, + size: size_t, +) -> size_t { + if size == 0 { + return 0; + } + sparc_code_impl( + now_pos, + is_encoder, + core::slice::from_raw_parts_mut(buffer, size), + ) +} +unsafe fn sparc_coder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, + is_encoder: bool, +) -> lzma_ret { + lzma_simple_coder_init( + next, + allocator, + filters, + Some(sparc_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t), + 0, + 4, + 4, + is_encoder, + ) +} +pub(crate) unsafe extern "C" fn lzma_simple_sparc_encoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + sparc_coder_init(next, allocator, filters, true) +} +pub(crate) unsafe extern "C" fn lzma_simple_sparc_decoder_init( + next: *mut lzma_next_coder, + allocator: *const lzma_allocator, + filters: *const lzma_filter_info, +) -> lzma_ret { + sparc_coder_init(next, allocator, filters, false) +} diff --git a/liblzma-rs/src/simple/x86.rs b/xz/src/simple/x86.rs similarity index 84% rename from liblzma-rs/src/simple/x86.rs rename to xz/src/simple/x86.rs index 41bca8a3..ab383e2a 100644 --- a/liblzma-rs/src/simple/x86.rs +++ b/xz/src/simple/x86.rs @@ -88,35 +88,31 @@ unsafe extern "C" fn x86_code( (*simple).prev_pos = prev_pos; buffer_pos } -extern "C" fn x86_coder_init( +unsafe fn x86_coder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, is_encoder: bool, ) -> lzma_ret { - return unsafe { - let ret: lzma_ret = lzma_simple_coder_init( - next, - allocator, - filters, - Some( - x86_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t, - ), - core::mem::size_of::(), - 5, - 1, - is_encoder, - ); - if ret == LZMA_OK { - let coder: *mut lzma_simple_coder = (*next).coder as *mut lzma_simple_coder; - let simple: *mut lzma_simple_x86 = (*coder).simple as *mut lzma_simple_x86; - (*simple).prev_mask = 0; - (*simple).prev_pos = (-5_i32) as u32; - } - ret - }; + let ret: lzma_ret = lzma_simple_coder_init( + next, + allocator, + filters, + Some(x86_code as unsafe extern "C" fn(*mut c_void, u32, bool, *mut u8, size_t) -> size_t), + core::mem::size_of::(), + 5, + 1, + is_encoder, + ); + if ret == LZMA_OK { + let coder: *mut lzma_simple_coder = (*next).coder as *mut lzma_simple_coder; + let simple: *mut lzma_simple_x86 = (*coder).simple as *mut lzma_simple_x86; + (*simple).prev_mask = 0; + (*simple).prev_pos = (-5_i32) as u32; + } + ret } -pub unsafe extern "C" fn lzma_simple_x86_encoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_x86_encoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, @@ -136,7 +132,7 @@ pub unsafe fn lzma_bcj_x86_encode(start_offset: u32, buf: *mut u8, size: size_t) size, ) } -pub unsafe extern "C" fn lzma_simple_x86_decoder_init( +pub(crate) unsafe extern "C" fn lzma_simple_x86_decoder_init( next: *mut lzma_next_coder, allocator: *const lzma_allocator, filters: *const lzma_filter_info, diff --git a/liblzma-rs/src/tuklib/mod.rs b/xz/src/tuklib/mod.rs similarity index 100% rename from liblzma-rs/src/tuklib/mod.rs rename to xz/src/tuklib/mod.rs diff --git a/liblzma-rs/src/tuklib/tuklib_cpucores.rs b/xz/src/tuklib/tuklib_cpucores.rs similarity index 100% rename from liblzma-rs/src/tuklib/tuklib_cpucores.rs rename to xz/src/tuklib/tuklib_cpucores.rs diff --git a/liblzma-rs/src/tuklib/tuklib_physmem.rs b/xz/src/tuklib/tuklib_physmem.rs similarity index 100% rename from liblzma-rs/src/tuklib/tuklib_physmem.rs rename to xz/src/tuklib/tuklib_physmem.rs diff --git a/liblzma-rs/src/types.rs b/xz/src/types.rs similarity index 97% rename from liblzma-rs/src/types.rs rename to xz/src/types.rs index 57dfa52e..21bf1a8e 100644 --- a/liblzma-rs/src/types.rs +++ b/xz/src/types.rs @@ -635,21 +635,12 @@ pub struct lzma_lzma1_encoder_s { pub type lzma_lzma1_encoder = lzma_lzma1_encoder_s; #[inline] pub fn read32le(buf: *const u8) -> u32 { - return unsafe { - let mut num: u32 = *buf as u32; - num |= (*buf.offset(1) as u32) << 8; - num |= (*buf.offset(2) as u32) << 16; - num |= (*buf.offset(3) as u32) << 24; - num - }; + unsafe { core::ptr::read_unaligned(buf.cast::()).to_le() } } #[inline] pub fn write32le(buf: *mut u8, num: u32) { unsafe { - *buf = num as u8; - *buf.offset(1) = (num >> 8) as u8; - *buf.offset(2) = (num >> 16) as u8; - *buf.offset(3) = (num >> 24) as u8; + core::ptr::write_unaligned(buf.cast::(), num.to_le()); } } pub type __uint32_t = u32; @@ -1226,7 +1217,7 @@ pub fn lzma_outq_outbuf_memusage(buf_size: size_t) -> u64 { pub unsafe fn aligned_read32ne(buf: *const u8) -> u32 { *(buf as *const u32) } -pub type rc_symbol = c_uint; +pub type rc_symbol = u8; pub const RC_FLUSH: rc_symbol = 4; pub const RC_DIRECT_1: rc_symbol = 3; pub const RC_DIRECT_0: rc_symbol = 2; @@ -1328,8 +1319,8 @@ pub use crate::check::check::{ lzma_check_finish, lzma_check_init, lzma_check_is_supported, lzma_check_size, lzma_check_update, }; pub use crate::check::crc32_fast::lzma_crc32; -pub use crate::common::block_decoder::lzma_block_decoder_init; -pub use crate::common::block_encoder::lzma_block_encoder_init; +pub(crate) use crate::common::block_decoder::lzma_block_decoder_init; +pub(crate) use crate::common::block_encoder::lzma_block_encoder_init; pub use crate::common::block_header_decoder::lzma_block_header_decode; pub use crate::common::block_header_encoder::{lzma_block_header_encode, lzma_block_header_size}; pub use crate::common::block_util::lzma_block_unpadded_size; @@ -1347,7 +1338,7 @@ pub use crate::common::index::{ lzma_index_append, lzma_index_end, lzma_index_init, lzma_index_memusage, lzma_index_padding_size, lzma_index_size, }; -pub use crate::common::index_encoder::lzma_index_encoder_init; +pub(crate) use crate::common::index_encoder::lzma_index_encoder_init; pub use crate::common::index_hash::{ lzma_index_hash_append, lzma_index_hash_decode, lzma_index_hash_end, lzma_index_hash_init, lzma_index_hash_size, @@ -1356,7 +1347,7 @@ pub use crate::common::outqueue::{ lzma_outq_end, lzma_outq_get_buf, lzma_outq_init, lzma_outq_is_readable, lzma_outq_prealloc_buf, lzma_outq_read, }; -pub use crate::common::stream_decoder::lzma_stream_decoder_init; +pub(crate) use crate::common::stream_decoder::lzma_stream_decoder_init; pub use crate::common::stream_flags_common::lzma_stream_flags_compare; pub use crate::common::stream_flags_decoder::{ lzma_stream_footer_decode, lzma_stream_header_decode, @@ -1367,15 +1358,16 @@ pub use crate::common::stream_flags_encoder::{ pub use crate::common::vli_decoder::lzma_vli_decode; pub use crate::common::vli_encoder::lzma_vli_encode; pub use crate::common::vli_size::lzma_vli_size; -pub use crate::delta::delta_common::{lzma_delta_coder_init, lzma_delta_coder_memusage}; +pub use crate::delta::delta_common::lzma_delta_coder_init; +pub(crate) use crate::delta::delta_common::lzma_delta_coder_memusage; pub use crate::lz::lz_encoder_mf::{lzma_mf_find, lzma_mf_find_raw}; pub use crate::lzma::fastpos_table::lzma_fastpos; -pub use crate::lzma::lzma_decoder::{ - lzma_lzma_decoder_init, lzma_lzma_decoder_memusage_nocheck, lzma_lzma_lclppb_decode, -}; -pub use crate::lzma::lzma_encoder::{ - lzma_lzma_encoder_init, lzma_lzma_encoder_memusage, lzma_lzma_lclppb_encode, +pub use crate::lzma::lzma_decoder::lzma_lzma_lclppb_decode; +pub(crate) use crate::lzma::lzma_decoder::{ + lzma_lzma_decoder_init, lzma_lzma_decoder_memusage_nocheck, }; +pub use crate::lzma::lzma_encoder::lzma_lzma_lclppb_encode; +pub(crate) use crate::lzma::lzma_encoder::{lzma_lzma_encoder_init, lzma_lzma_encoder_memusage}; pub use crate::lzma::lzma_encoder_presets::lzma_lzma_preset; pub use crate::rangecoder::price_table::lzma_rc_prices; pub use crate::simple::simple_coder::lzma_simple_coder_init;