blosc2-rs-0.4.0+2.15.2/.cargo/config000064400000000000000000000001571046102023000145200ustar 00000000000000[target.x86_64-apple-darwin] rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ] blosc2-rs-0.4.0+2.15.2/.cargo_vcs_info.json0000644000000001360000000000100133640ustar { "git": { "sha1": "4bcfbe4e824b34755a4b16e2de1fb453286a7f5a" }, "path_in_vcs": "" }blosc2-rs-0.4.0+2.15.2/Cargo.lock0000644000000640340000000000100113460ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bindgen" version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", "itertools 0.12.1", "lazy_static", "lazycell", "log", "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", "which", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blosc2-rs" version = "0.4.0+2.15.2" dependencies = [ "blosc2-sys", "criterion", "ctor", "parking_lot", "rand", ] [[package]] name = "blosc2-sys" version = "0.4.0+2.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a780fec12b1352d5d7d87858d192ecba0bd220310a35dacc18756fe58139871" dependencies = [ "bindgen", "cmake", "copy_dir", "libc", "pkg-config", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" dependencies = [ "shlex", ] [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "clap" version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "bitflags 1.3.2", "clap_lex", "indexmap", "textwrap", ] [[package]] name = "clap_lex" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] [[package]] name = "cmake" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ "cc", ] [[package]] name = "copy_dir" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "543d1dd138ef086e2ff05e3a48cf9da045da2033d16f8538fd76b86cd49b2ca3" dependencies = [ "walkdir", ] [[package]] name = "criterion" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ "anes", "atty", "cast", "ciborium", "clap", "criterion-plot", "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools 0.10.5", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "ctor" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", "syn", ] [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "half" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "home" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets", ] [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "os_str_bytes" version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] [[package]] name = "prettyplease" version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_syscall" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "textwrap" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "which" version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", "home", "once_cell", "rustix", ] [[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.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[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-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn", ] blosc2-rs-0.4.0+2.15.2/Cargo.toml0000644000000034020000000000100113610ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "blosc2-rs" version = "0.4.0+2.15.2" build = false exclude = [ ".gitignore", ".gitmodules", ".github/*", "benches/*", "data/*", "environment.yml", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Blosc2" readme = "README.md" license = "MIT" [lib] name = "blosc2" path = "src/lib.rs" [[example]] name = "schunk_simple" path = "examples/schunk_simple.rs" [[example]] name = "simple" path = "examples/simple.rs" [dependencies.blosc2-sys] version = "0.4.0+2.15.2" [dependencies.parking_lot] version = "^0.12" [dev-dependencies.criterion] version = "0.4" features = ["html_reports"] [dev-dependencies.ctor] version = "0.2.0" [dev-dependencies.rand] version = "0.8.5" [features] deactivate-zlib = ["blosc2-sys/deactivate-zlib"] deactivate-zlib-optim = ["blosc2-sys/deactivate-zlib-optim"] deactivate-zstd = ["blosc2-sys/deactivate-zstd"] default = ["shared"] prefer-external-lz4 = ["blosc2-sys/prefer-external-lz4"] prefer-external-zlib = ["blosc2-sys/prefer-external-zlib"] prefer-external-zstd = ["blosc2-sys/prefer-external-zstd"] regenerate-bindings = ["blosc2-sys/regenerate-bindings"] shared = ["blosc2-sys/shared"] static = ["blosc2-sys/static"] use-system-blosc2 = ["blosc2-sys/use-system-blosc2"] blosc2-rs-0.4.0+2.15.2/Cargo.toml.orig000064400000000000000000000022621046102023000150450ustar 00000000000000[package] name = "blosc2-rs" version = "0.4.0+2.15.2" description = "Blosc2" license = "MIT" edition = "2021" exclude = [ ".gitignore", ".gitmodules", ".github/*", "benches/*", "data/*", "environment.yml", ] [lib] name = "blosc2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] default = ["shared"] use-system-blosc2 = ["blosc2-sys/use-system-blosc2"] regenerate-bindings = ["blosc2-sys/regenerate-bindings"] static = ["blosc2-sys/static"] shared = ["blosc2-sys/shared"] deactivate-zlib = ["blosc2-sys/deactivate-zlib"] prefer-external-zlib = ["blosc2-sys/prefer-external-zlib"] deactivate-zstd = ["blosc2-sys/deactivate-zstd"] prefer-external-zstd = ["blosc2-sys/prefer-external-zstd"] prefer-external-lz4 = ["blosc2-sys/prefer-external-lz4"] deactivate-zlib-optim = ["blosc2-sys/deactivate-zlib-optim"] [dependencies] blosc2-sys = { path = "blosc2-sys", version = "0.4.0+2.15.2" } parking_lot = "^0.12" [dev-dependencies] ctor = "0.2.0" criterion = { version = "0.4", features = ["html_reports"] } rand = "0.8.5" [[bench]] name = "benchmarks" harness = false blosc2-rs-0.4.0+2.15.2/LICENSE000064400000000000000000000020561046102023000131640ustar 00000000000000MIT License Copyright (c) 2020 Miles Granger Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. blosc2-rs-0.4.0+2.15.2/README.md000064400000000000000000000007501046102023000134350ustar 00000000000000# blosc2-rs [![CI](https://github.com/milesgranger/blosc2-rs/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/milesgranger/blosc2-rs/actions/workflows/CI.yml) [![Latest version](https://img.shields.io/crates/v/blosc2-rs.svg)](https://crates.io/crates/blosc2-rs) [![Documentation](https://docs.rs/blosc2-rs/badge.svg)](https://docs.rs/blosc2-rs) ![License](https://img.shields.io/crates/l/blosc2-rs.svg) Rust bindings for [c-blosc2](https://github.com/Blosc/c-blosc2) blosc2-rs-0.4.0+2.15.2/examples/schunk_simple.rs000064400000000000000000000050611046102023000172060ustar 00000000000000const KB: usize = 1024; const MB: usize = 1024 * KB; const CHUNKSIZE: usize = 1_000 * 1_000; const NCHUNKS: usize = 100; const NTHREADS: usize = 4; fn main() { let _blosc2_guard = blosc2::Blosc2Guard::get_or_init(); let mut data = vec![0_i32; CHUNKSIZE]; let mut data_dest = vec![0_i32; CHUNKSIZE]; println!( "Blosc2 version info: {} ({})", blosc2::get_version_string().unwrap(), blosc2::BLOSC2_VERSION_DATE ); // Create a super-chunk container let cparams = blosc2::CParams::default() .set_typesize::() .set_clevel(blosc2::CLevel::Nine) .set_nthreads(NTHREADS); let dparams = blosc2::DParams::default().set_nthreads(NTHREADS); let storage = blosc2::schunk::Storage::default() .set_cparams(cparams) .set_dparams(dparams); let mut schunk = blosc2::schunk::SChunk::new(storage); let ttotal = std::time::Instant::now(); for nchunk in 0..NCHUNKS { for i in 0..CHUNKSIZE { data[i] = (i * nchunk) as i32; } let nchunks = schunk.append_buffer(&data).unwrap(); if nchunks != nchunk + 1 { panic!( "Unexpected nchunks! Got {}, but expected {}", nchunks, nchunk + 1 ); } } println!( "Compression ratio: {:.1} MB -> {:.1} MB ({:.1}x)", schunk.nbytes() as f32 / MB as f32, schunk.cbytes() as f32 / MB as f32, schunk.compression_ratio() ); println!( "Compression time: {:.3}s, {:.1}MB/s", ttotal.elapsed().as_secs_f32(), schunk.nbytes() as f32 / (ttotal.elapsed().as_secs_f32() * MB as f32) ); // Retrieve and decompress the chunks (0-based count) let ttotal = std::time::Instant::now(); for nchunk in (0..(NCHUNKS - 1)).rev() { // The error check in c-blosc2 example is removed b/c will have been raised thru .unwrap call let dsize = schunk.decompress_chunk(nchunk, &mut data_dest).unwrap(); assert_eq!(dsize, CHUNKSIZE); } println!( "Decompression time: {:.3}s, {:.1}MB/s", ttotal.elapsed().as_secs_f32(), schunk.nbytes() as f32 / (ttotal.elapsed().as_secs_f32() * MB as f32) ); // Check integrity of the second chunk (made of non-zeros) schunk.decompress_chunk(1, &mut data_dest).unwrap(); for i in 0..CHUNKSIZE { if data_dest[i] != i as i32 { panic!( "Decompressed data differs from original {}, {}", i as i32, data_dest[i] ); } } } blosc2-rs-0.4.0+2.15.2/examples/simple.rs000064400000000000000000000006471046102023000156400ustar 00000000000000use blosc2::{compress, decompress, Blosc2Guard}; fn main() { let _blosc2_guard = Blosc2Guard::get_or_init(); let data = std::iter::repeat(b"some data here") .take(100_000) .flat_map(|v| v.to_vec()) .collect::>(); let compressed = compress(&data, None, None, None, None).unwrap(); let decompressed = decompress(&compressed).unwrap(); assert_eq!(data, decompressed); } blosc2-rs-0.4.0+2.15.2/src/lib.rs000064400000000000000000002050311046102023000140600ustar 00000000000000//! Blosc2 Rust bindings. use blosc2_sys as ffi; use parking_lot::{Mutex, RwLock}; use std::ffi::{c_void, CStr, CString}; use std::sync::{Arc, OnceLock}; use std::{io, mem}; pub const BLOSC2_VERSION_DATE: &'static str = unsafe { std::str::from_utf8_unchecked(blosc2_sys::BLOSC2_VERSION_DATE) }; pub const BLOSC2_VERSION_STRING: &'static str = unsafe { std::str::from_utf8_unchecked(blosc2_sys::BLOSC2_VERSION_STRING) }; pub use blosc2_sys::{ BLOSC2_MAX_DIM, BLOSC2_VERSION_MAJOR, BLOSC2_VERSION_MINOR, BLOSC2_VERSION_RELEASE, }; const BLOSC2_GUARD: OnceLock> = OnceLock::new(); const BLOSC2_INIT_FLAG: OnceLock>> = OnceLock::new(); /// Result type used in this library pub type Result = std::result::Result; #[derive(Debug)] pub enum Error { /// A Blosc2 library specific error. Often mapped to the /// raw error return code Blosc2(Blosc2Error), /// Any other error, converted into a string Other(String), } impl From for Error { fn from(err: Blosc2Error) -> Self { Error::Blosc2(err) } } impl From for Error { fn from(err: String) -> Self { Error::Other(err) } } impl<'a> From<&'a str> for Error { fn from(err: &'a str) -> Self { Error::Other(err.to_string()) } } impl From for io::Error { fn from(err: Error) -> io::Error { io::Error::new(io::ErrorKind::Other, err.to_string()) } } impl std::error::Error for Error {} impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } /// Possible errors arising from Blosc2 library #[derive(Debug)] #[repr(i32)] pub enum Blosc2Error { /// Generic failure Failure = ffi::BLOSC2_ERROR_FAILURE, /// Bad stream Stream = ffi::BLOSC2_ERROR_STREAM, /// Invalid data Data = ffi::BLOSC2_ERROR_DATA, /// Memory alloc/realloc failure MemoryAlloc = ffi::BLOSC2_ERROR_MEMORY_ALLOC, /// Not enough space to read ReadBuffer = ffi::BLOSC2_ERROR_READ_BUFFER, /// Not enough space to write WriteBuffer = ffi::BLOSC2_ERROR_WRITE_BUFFER, /// Codec not supported CodecSupport = ffi::BLOSC2_ERROR_CODEC_SUPPORT, /// Invalid parameter supplied to codec CodecParam = ffi::BLOSC2_ERROR_CODEC_PARAM, /// Codec dictionary error CodecDict = ffi::BLOSC2_ERROR_CODEC_DICT, /// Version not supported VersionSupport = ffi::BLOSC2_ERROR_VERSION_SUPPORT, /// Invalid value in header InvalidHeader = ffi::BLOSC2_ERROR_INVALID_HEADER, /// Invalid parameter supplied to function InvalidParam = ffi::BLOSC2_ERROR_INVALID_PARAM, /// File read failure FileRead = ffi::BLOSC2_ERROR_FILE_READ, /// File write failure FileWrite = ffi::BLOSC2_ERROR_FILE_WRITE, /// File open failure FileOpen = ffi::BLOSC2_ERROR_FILE_OPEN, /// Not found NotFound = ffi::BLOSC2_ERROR_NOT_FOUND, /// Bad run length encoding RunLength = ffi::BLOSC2_ERROR_RUN_LENGTH, /// Filter pipeline error FilterPipeline = ffi::BLOSC2_ERROR_FILTER_PIPELINE, /// Chunk insert failure ChunkInsert = ffi::BLOSC2_ERROR_CHUNK_INSERT, /// Chunk append failure ChunkAppend = ffi::BLOSC2_ERROR_CHUNK_APPEND, /// Chunk update failure ChunkUpdate = ffi::BLOSC2_ERROR_CHUNK_UPDATE, /// Sizes larger than 2gb not supported TwoGBLimit = ffi::BLOSC2_ERROR_2GB_LIMIT, /// Super-chunk copy failure SchunkCopy = ffi::BLOSC2_ERROR_SCHUNK_COPY, /// Wrong type for frame FrameType = ffi::BLOSC2_ERROR_FRAME_TYPE, /// File truncate failure FileTruncate = ffi::BLOSC2_ERROR_FILE_TRUNCATE, /// Thread or thread context creation failure ThreadCreate = ffi::BLOSC2_ERROR_THREAD_CREATE, /// Postfilter failure PostFilter = ffi::BLOSC2_ERROR_POSTFILTER, /// Special frame failure FrameSpecial = ffi::BLOSC2_ERROR_FRAME_SPECIAL, /// Special super-chunk failure SchunkSpecial = ffi::BLOSC2_ERROR_SCHUNK_SPECIAL, /// IO plugin error PluginIO = ffi::BLOSC2_ERROR_PLUGIN_IO, /// Remove file failure FileRemove = ffi::BLOSC2_ERROR_FILE_REMOVE, /// Pointer is null NullPointer = ffi::BLOSC2_ERROR_NULL_POINTER, /// Invalid index InvalidIndex = ffi::BLOSC2_ERROR_INVALID_INDEX, /// Metalayer has not been found MetalayerNotFound = ffi::BLOSC2_ERROR_METALAYER_NOT_FOUND, } impl std::fmt::Display for Blosc2Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } impl From for Blosc2Error { fn from(code: i32) -> Self { match code { ffi::BLOSC2_ERROR_FAILURE => Blosc2Error::Failure, ffi::BLOSC2_ERROR_STREAM => Blosc2Error::Stream, ffi::BLOSC2_ERROR_DATA => Blosc2Error::Data, ffi::BLOSC2_ERROR_MEMORY_ALLOC => Blosc2Error::MemoryAlloc, ffi::BLOSC2_ERROR_READ_BUFFER => Blosc2Error::ReadBuffer, ffi::BLOSC2_ERROR_WRITE_BUFFER => Blosc2Error::WriteBuffer, ffi::BLOSC2_ERROR_CODEC_SUPPORT => Blosc2Error::CodecSupport, ffi::BLOSC2_ERROR_CODEC_PARAM => Blosc2Error::CodecParam, ffi::BLOSC2_ERROR_CODEC_DICT => Blosc2Error::CodecDict, ffi::BLOSC2_ERROR_VERSION_SUPPORT => Blosc2Error::VersionSupport, ffi::BLOSC2_ERROR_INVALID_HEADER => Blosc2Error::InvalidHeader, ffi::BLOSC2_ERROR_INVALID_PARAM => Blosc2Error::InvalidParam, ffi::BLOSC2_ERROR_FILE_READ => Blosc2Error::FileRead, ffi::BLOSC2_ERROR_FILE_WRITE => Blosc2Error::FileWrite, ffi::BLOSC2_ERROR_FILE_OPEN => Blosc2Error::FileOpen, ffi::BLOSC2_ERROR_NOT_FOUND => Blosc2Error::NotFound, ffi::BLOSC2_ERROR_RUN_LENGTH => Blosc2Error::RunLength, ffi::BLOSC2_ERROR_FILTER_PIPELINE => Blosc2Error::FilterPipeline, ffi::BLOSC2_ERROR_CHUNK_INSERT => Blosc2Error::ChunkInsert, ffi::BLOSC2_ERROR_CHUNK_APPEND => Blosc2Error::ChunkAppend, ffi::BLOSC2_ERROR_CHUNK_UPDATE => Blosc2Error::ChunkUpdate, ffi::BLOSC2_ERROR_2GB_LIMIT => Blosc2Error::TwoGBLimit, ffi::BLOSC2_ERROR_SCHUNK_COPY => Blosc2Error::SchunkCopy, ffi::BLOSC2_ERROR_FRAME_TYPE => Blosc2Error::FrameType, ffi::BLOSC2_ERROR_FILE_TRUNCATE => Blosc2Error::FileTruncate, ffi::BLOSC2_ERROR_THREAD_CREATE => Blosc2Error::ThreadCreate, ffi::BLOSC2_ERROR_POSTFILTER => Blosc2Error::PostFilter, ffi::BLOSC2_ERROR_FRAME_SPECIAL => Blosc2Error::FrameSpecial, ffi::BLOSC2_ERROR_SCHUNK_SPECIAL => Blosc2Error::SchunkSpecial, ffi::BLOSC2_ERROR_PLUGIN_IO => Blosc2Error::PluginIO, ffi::BLOSC2_ERROR_FILE_REMOVE => Blosc2Error::FileRemove, ffi::BLOSC2_ERROR_NULL_POINTER => Blosc2Error::NullPointer, ffi::BLOSC2_ERROR_INVALID_INDEX => Blosc2Error::InvalidIndex, ffi::BLOSC2_ERROR_METALAYER_NOT_FOUND => Blosc2Error::MetalayerNotFound, _ => panic!("Error code {} not matched in existing Error codes", code), } } } /// Default buffer size for intermediate de/compression results when required pub const BUFSIZE: usize = 8196_usize; /// Possible Filters #[derive(Copy, Clone)] pub enum Filter { NoFilter = ffi::BLOSC_NOFILTER as _, Shuffle = ffi::BLOSC_SHUFFLE as _, BitShuffle = ffi::BLOSC_BITSHUFFLE as _, Delta = ffi::BLOSC_DELTA as _, TruncPrec = ffi::BLOSC_TRUNC_PREC as _, LastFilter = ffi::BLOSC_LAST_FILTER as _, LastRegisteredFilter = ffi::BLOSC_LAST_REGISTERED_FILTER as _, } impl Default for Filter { fn default() -> Self { Filter::Shuffle } } impl ToString for Filter { fn to_string(&self) -> String { match self { Self::NoFilter => "nofilter", Self::Shuffle => "shuffle", Self::BitShuffle => "bitshuffle", Self::Delta => "delta", Self::TruncPrec => "truncprec", Self::LastFilter => "lastfilter", Self::LastRegisteredFilter => "lastregisteredfilter", } .to_string() } } impl<'a> TryFrom<&'a str> for Filter { type Error = Error; fn try_from(val: &'a str) -> Result { match val.to_lowercase().as_str() { "nofilter" => Ok(Filter::NoFilter), "shuffle" => Ok(Filter::Shuffle), "bitshuffle" => Ok(Filter::BitShuffle), "delta" => Ok(Filter::Delta), "trunctprec" => Ok(Filter::TruncPrec), "lastfilter" => Ok(Filter::LastFilter), "lastregisteredfilter" => Ok(Filter::LastRegisteredFilter), _ => Err(Error::from(format!("No matching filter for '{}'", val))), } } } /// Possible compression codecs #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Codec { BloscLz = ffi::BLOSC_BLOSCLZ as _, LZ4 = ffi::BLOSC_LZ4 as _, LZ4HC = ffi::BLOSC_LZ4HC as _, ZLIB = ffi::BLOSC_ZLIB as _, ZSTD = ffi::BLOSC_ZSTD as _, LastCodec = ffi::BLOSC_LAST_CODEC as _, LastRegisteredCodec = ffi::BLOSC_LAST_REGISTERED_CODEC as _, } impl Codec { #[allow(dead_code)] fn to_name(&self) -> Result { (*self).try_into() } fn to_name_cstring(&self) -> Result { let mut compname = std::ptr::null(); let rc = unsafe { ffi::blosc2_compcode_to_compname(*self as _, &mut compname) }; if rc == -1 { return Err(Error::Other(format!("Unsupported Codec {:?}", self))); } unsafe { Ok(CStr::from_ptr(compname as _).to_owned()) } } } impl TryInto for Codec { type Error = Error; fn try_into(self) -> Result { self.clone() .to_name_cstring()? .into_string() .map_err(|e| Error::Other(e.to_string())) } } impl<'a> TryFrom<&'a str> for Codec { type Error = Error; fn try_from(value: &'a str) -> Result { let compname = CString::new(value).map_err(|e| Error::Other(e.to_string()))?; let compcode = unsafe { ffi::blosc2_compname_to_compcode(compname.as_ptr()) }; if compcode == -1 { return Err(Error::from(format!("Compcode {} not recognized", value))); } Codec::try_from(compcode) } } impl TryFrom for Codec { type Error = Error; fn try_from(compcode: i32) -> Result { match compcode as _ { ffi::BLOSC_BLOSCLZ => Ok(Codec::BloscLz), ffi::BLOSC_LZ4 => Ok(Codec::LZ4), ffi::BLOSC_LZ4HC => Ok(Codec::LZ4HC), ffi::BLOSC_ZLIB => Ok(Codec::ZLIB), ffi::BLOSC_ZSTD => Ok(Codec::ZSTD), ffi::BLOSC_LAST_CODEC => Ok(Codec::LastCodec), ffi::BLOSC_LAST_REGISTERED_CODEC => Ok(Codec::LastRegisteredCodec), _ => Err(format!("Not match for compcode {}", compcode).into()), } } } impl Default for Codec { fn default() -> Self { Codec::BloscLz } } /// Possible CLevel settings #[repr(u8)] pub enum CLevel { Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6, Seven = 7, Eight = 8, Nine = 9, } impl Default for CLevel { fn default() -> Self { CLevel::Nine // Ref blosc2 python default } } impl TryFrom for CLevel { type Error = Error; fn try_from(val: usize) -> Result { match val { 0 => Ok(CLevel::Zero), 1 => Ok(CLevel::One), 2 => Ok(CLevel::Two), 3 => Ok(CLevel::Three), 4 => Ok(CLevel::Four), 5 => Ok(CLevel::Five), 6 => Ok(CLevel::Six), 7 => Ok(CLevel::Seven), 8 => Ok(CLevel::Eight), 9 => Ok(CLevel::Nine), _ => Err(Error::from(format!( "Compression level must be 0-9, got {}", val ))), } } } pub mod schunk { //! `blosc2_schunk`,`blosc2_storage`, and `Chunk` APIs use std::ffi::CStr; use std::io; use std::path::{Path, PathBuf}; use super::*; /// Wrapper to [blosc2_storage] /// /// [blosc2_storage]: blosc2_sys::blosc2_storage /// /// Example /// ------- /// ``` /// use blosc2::schunk::Storage; /// /// let storage = Storage::default().set_urlpath("/some/path.blosc2"); /// ``` pub struct Storage { inner: ffi::blosc2_storage, cparams: CParams, dparams: DParams, } impl Default for Storage { fn default() -> Self { let storage = unsafe { ffi::blosc2_get_blosc2_storage_defaults() }; Storage { inner: storage, cparams: CParams::default(), dparams: DParams::default(), } } } impl Storage { /// Set url/file path to specify a file-backed `schunk`. /// if not set, defaults to an in-memory `schunk` pub fn set_urlpath>(mut self, urlpath: S) -> Result { self.inner.urlpath = CString::new(urlpath.as_ref().to_string_lossy().to_string()) .map_err(|e| Error::Other(e.to_string()))? .into_raw(); Ok(self) } /// Reference to the urlpath (if any) /// /// Example /// ------- /// ``` /// use blosc2::schunk::Storage; /// /// let storage = Storage::default().set_urlpath("/some/path.blosc2").unwrap(); /// assert_eq!(storage.get_urlpath().unwrap().unwrap(), "/some/path.blosc2"); /// ``` pub fn get_urlpath(&self) -> Result> { if self.inner.urlpath.is_null() { return Ok(None); } unsafe { CStr::from_ptr(self.inner.urlpath) .to_str() .map(|v| Some(v)) .map_err(|e| Error::Other(e.to_string())) } } /// Set the contiguous nature of the `schunk`. pub fn set_contiguous(mut self, contiguous: bool) -> Self { self.inner.contiguous = contiguous; self } /// Set compression parameters pub fn set_cparams(mut self, cparams: CParams) -> Self { self.cparams = cparams; self.inner.cparams = &mut self.cparams.0; self } /// Get compression parameters pub fn get_cparams(&self) -> &CParams { &self.cparams } /// Set decompression parameters pub fn set_dparams(mut self, dparams: DParams) -> Self { self.dparams = dparams; self.inner.dparams = &mut self.dparams.0; self } } /// Wraps a single chunk of a super-chunk. /// /// Normally constructed via `Chunk::from_schunk` /// /// Example /// ------- /// ``` /// use std::io::Write; /// use blosc2::{CParams, DParams, Blosc2Guard}; /// use blosc2::schunk::{Storage, SChunk, Chunk}; /// /// let _guard = Blosc2Guard::get_or_init(); /// /// let input = b"some data"; /// let storage = Storage::default() /// .set_contiguous(true) /// .set_cparams(CParams::from(&input[0])) /// .set_dparams(DParams::default()); /// let mut schunk = SChunk::new(storage); /// /// let n = schunk.write(input).unwrap(); // same as schunk.append_buffer(input)?; /// assert_eq!(n as usize, input.len()); /// assert_eq!(schunk.n_chunks(), 1); /// /// let chunk = Chunk::from_schunk(&mut schunk, 0).unwrap(); // Get first (and only) chunk /// assert_eq!(chunk.info().unwrap().nbytes() as usize, input.len()); /// ``` #[derive(Clone)] pub struct Chunk { pub(crate) chunk: Arc>, pub(crate) needs_free: bool, } unsafe impl Sync for Chunk {} unsafe impl Send for Chunk {} impl TryFrom> for Chunk { type Error = Error; #[inline] fn try_from(v: Vec) -> Result { Self::from_vec(v) } } impl Chunk { /// Create a new `Chunk` directly from a pointer, you probably /// want `Chunk::from_schunk` instead. pub fn new(chunk: *mut u8, needs_free: bool) -> Self { Self { chunk: Arc::new(RwLock::new(chunk)), needs_free, } } /// Construct Chunk from vector of bytes, this Vec is assumed to be the result of a valid /// chunk de/compression or other initialization method like uinit/zeros etc. /// /// Example /// ------- /// ``` /// use blosc2::{schunk::Chunk, compress}; /// /// let buf: Vec = compress(&vec![0i32, 1, 2, 3, 4], None, None, None, None).unwrap(); /// assert!(Chunk::from_vec(buf).is_ok()); /// ``` #[inline] pub fn from_vec(v: Vec) -> Result { let mut v = v; v.shrink_to_fit(); if let Err(_) = CompressedBufferInfo::try_from(v.as_slice()) { return Err("Appears this buffer is not a valid blosc2 chunk".into()); } let ptr = v.as_mut_ptr(); mem::forget(v); Ok(Self::new(ptr as _, true)) } /// Export this Chunk into a `Vec` /// Maybe clone underlying vec if it's managed by blosc2 pub fn into_vec(self) -> Result> { let info = self.info()?; let buf = unsafe { Vec::from_raw_parts(*self.chunk.write(), info.cbytes(), info.cbytes()) }; if !self.needs_free { return Ok(buf.clone()); } Ok(buf) } /// Get the raw buffer of this chunk pub fn as_slice(&self) -> Result<&[u8]> { let info = CompressedBufferInfo::try_from(*self.chunk.read() as *const c_void)?; let slice = unsafe { std::slice::from_raw_parts(*self.chunk.read(), info.cbytes()) }; Ok(slice) } /// Return the number of elements in the compressed Chunk /// /// Example /// ------- /// ``` /// use blosc2::{schunk::Chunk, compress}; /// /// let chunk: Chunk = compress(&vec![0i32, 1, 2, 3, 4], None, None, None, None) /// .unwrap() /// .try_into() /// .unwrap(); /// assert_eq!(chunk.len::().unwrap(), 5); /// ``` #[inline] pub fn len(&self) -> Result { CompressedBufferInfo::try_from(*self.chunk.read() as *const c_void) .map(|info| info.nbytes() / mem::size_of::()) } #[inline] pub fn getitems(&self, offset: usize, n_items: usize) -> Result> { if self.len::()? < offset + n_items { return Err(format!( "Would be out of bounds. Chunk contains {} elements", self.len::()? ) .into()); } getitems(self.as_slice()?, offset, n_items) } /// Create a chunk made of uninitialized values /// /// Examplek /// ------- /// ``` /// use blosc2::CParams; /// use blosc2::schunk::Chunk; /// /// let chunk = Chunk::uninit::(CParams::default(), 10).unwrap(); /// assert_eq!(chunk.info().unwrap().nbytes(), 10); /// ``` pub fn uninit(cparams: CParams, len: usize) -> Result { let mut cparams = cparams; if mem::size_of::() != cparams.0.typesize as usize { cparams.0.typesize = mem::size_of::() as _; } let mut dst = Vec::with_capacity( (len * cparams.0.typesize as usize) + ffi::BLOSC_EXTENDED_HEADER_LENGTH as usize, ); let nbytes = unsafe { ffi::blosc2_chunk_uninit( cparams.0, len as i32 * cparams.0.typesize, dst.as_mut_ptr() as *mut c_void, dst.capacity() as i32, ) }; if nbytes < 0 { return Err("Failed to create uninitialized chunk".into()); } unsafe { dst.set_len(nbytes as _) }; Self::from_vec(dst) } /// Create a chunk made of repeating a value /// /// Examplek /// ------- /// ``` /// use blosc2::CParams; /// use blosc2::schunk::Chunk; /// /// let mut chunk = Chunk::repeatval::(CParams::default().set_typesize::(), 0.123, 4).unwrap(); /// assert_eq!(chunk.info().unwrap().nbytes(), 16); // 4 elements * 4 bytes each /// assert_eq!(chunk.decompress::().unwrap(), vec![0.123_f32, 0.123, 0.123, 0.123]); /// ``` pub fn repeatval(cparams: CParams, value: T, len: usize) -> Result { let mut cparams = cparams; if mem::size_of::() != cparams.0.typesize as usize { cparams.0.typesize = mem::size_of::() as _; } let mut dst = Vec::with_capacity( (len * cparams.0.typesize as usize) + ffi::BLOSC_EXTENDED_HEADER_LENGTH as usize, ); let nbytes = unsafe { ffi::blosc2_chunk_repeatval( cparams.0, len as i32 * cparams.0.typesize, dst.as_mut_ptr() as _, dst.capacity() as _, &value as *const T as _, ) }; if nbytes < 0 { return Err("Failed to create chunk".into()); } unsafe { dst.set_len(nbytes as _) }; Self::from_vec(dst) } /// Create a chunk made of zeros /// /// Example /// ------- /// ``` /// use blosc2::CParams; /// use blosc2::schunk::Chunk; /// /// let cparams = CParams::default().set_typesize::(); /// let chunk = Chunk::zeros::(cparams, 10).unwrap(); /// assert_eq!(chunk.info().unwrap().nbytes(), 40); // 10 elements * 4 bytes each /// ``` pub fn zeros(cparams: CParams, len: usize) -> Result { let mut cparams = cparams; if mem::size_of::() != cparams.0.typesize as usize { cparams.0.typesize = mem::size_of::() as _; } let mut dst = Vec::with_capacity( (len * cparams.0.typesize as usize) + ffi::BLOSC_EXTENDED_HEADER_LENGTH as usize, ); let nbytes = unsafe { ffi::blosc2_chunk_zeros( cparams.0, len as i32 * cparams.0.typesize, dst.as_mut_ptr() as _, dst.capacity() as i32, ) }; if nbytes < 0 { return Err(Error::Blosc2(Blosc2Error::from(nbytes))); } unsafe { dst.set_len(nbytes as usize) }; Self::from_vec(dst) } /// Compression ratio of the `Chunk` /// /// Example /// ------- /// ``` /// use blosc2::schunk::Chunk; /// /// let chunk = Chunk::compress(&vec![0i32; 1_000], None, None, None, None).unwrap(); /// let ratio = chunk.compression_ratio().unwrap(); /// assert_eq!(ratio, 125.0); /// ``` pub fn compression_ratio(&self) -> Result { let info = self.info()?; if info.cbytes() == 0 { return Ok(0f32); } Ok(info.nbytes() as f32 / info.cbytes() as f32) } /// Helper method to construct a `Chunk` directly from compression. /// This is equivelent to: /// ``` /// use blosc2::{compress, schunk::Chunk}; /// /// let compressed = compress(&vec![0u8, 1, 2, 3], None, None, None, None).unwrap(); /// let chunk = Chunk::from_vec(compressed).unwrap(); /// assert_eq!(chunk.len::().unwrap(), 4); /// ``` #[inline] pub fn compress( src: &[T], typesize: Option, clevel: Option, filter: Option, codec: Option, ) -> Result { crate::compress(src, typesize, clevel, filter, codec).map(Self::from_vec)? } /// Decompress the current chunk /// /// Example /// ------- /// ``` /// use blosc2::CParams; /// use blosc2::schunk::Chunk; /// /// let cparams = CParams::default().set_typesize::(); /// let mut chunk = Chunk::zeros::(cparams, 5).unwrap(); /// /// assert_eq!(chunk.info().unwrap().nbytes(), 40); // 5 elements * 64bit == 40bytes /// let decompressed = chunk.decompress::().unwrap(); /// dbg!(decompressed.len()); /// assert_eq!(decompressed, vec![0i64; 5]); /// ``` pub fn decompress(&self) -> Result> { let slice = unsafe { std::slice::from_raw_parts(*self.chunk.read(), self.info()?.cbytes) }; crate::decompress(slice) } /// Create a new `Chunk` from a `SChunk` #[inline] pub fn from_schunk(schunk: &mut SChunk, nchunk: usize) -> Result { let mut chunk: *mut u8 = std::ptr::null_mut(); let mut needs_free: bool = false; let rc = unsafe { ffi::blosc2_schunk_get_chunk( *schunk.0.read(), nchunk as _, &mut chunk as _, &mut needs_free, ) }; if rc < 0 { return Err(Error::Blosc2(Blosc2Error::from(rc as i32))); } Ok(Self { chunk: Arc::new(RwLock::new(chunk)), needs_free, }) } /// Uncompressed bytes in this Chunk pub fn nbytes(&self) -> Result { self.info().map(|info| info.nbytes) } /// Compressed bytes in this Chunk pub fn cbytes(&self) -> Result { self.info().map(|info| info.cbytes) } /// Get `CompressedBufferInfo` for this chunk. #[inline] pub fn info(&self) -> Result { let mut nbytes = 0; let mut cbytes = 0; let mut blocksize = 0; let rc = unsafe { ffi::blosc2_cbuffer_sizes( *self.chunk.read() as _, &mut nbytes, &mut cbytes, &mut blocksize, ) }; if rc < 0 { return Err(Blosc2Error::from(rc).into()); } Ok(CompressedBufferInfo { nbytes: nbytes as _, cbytes: cbytes as _, blocksize: blocksize as _, }) } } impl Drop for Chunk { fn drop(&mut self) { // drop if needs freed and this is last strong ref if self.needs_free && Arc::strong_count(&self.chunk) == 1 { unsafe { blosc2_sys::libc::free(*self.chunk.write() as _) }; } } } /// Wrapper to [blosc2_schunk] /// /// [blosc2_schunk]: blosc2_sys::blosc2_schunk #[derive(Clone)] pub struct SChunk(pub(crate) Arc>); unsafe impl Send for SChunk {} // Loosely inspired by blosc2-python implementation impl SChunk { pub fn new(storage: Storage) -> Self { let mut storage = storage; let schunk = unsafe { ffi::blosc2_schunk_new(&mut storage.inner) }; Self(Arc::new(RwLock::new(schunk))) } pub fn copy(&self) -> Self { let schunk = unsafe { ffi::blosc2_schunk_copy(*self.0.read(), (**self.0.read()).storage) }; Self(Arc::new(RwLock::new(schunk))) } pub fn frame(&self) -> Result<&[u8]> { unsafe { if (**self.0.read()).frame.is_null() { return Err(Error::from("schunk frame is null")); } let len = ffi::blosc2_schunk_frame_len(*self.0.read()) as usize; let buf = std::slice::from_raw_parts((**self.0.read()).frame as _, len); Ok(buf) } } #[inline] pub(crate) fn inner(&self) -> &ffi::blosc2_schunk { unsafe { &(**self.0.read()) } } #[inline] #[allow(dead_code)] pub(crate) fn inner_mut(&mut self) -> &mut ffi::blosc2_schunk { unsafe { &mut (**self.0.write()) } } /// Append data to SChunk, returning new number of chunks #[inline] pub fn append_buffer(&mut self, data: &[T]) -> Result { if data.is_empty() { return Ok(self.inner().nchunks as usize); } let nbytes = mem::size_of::() * data.len(); let typesize = self.typesize(); if nbytes % self.typesize() != 0 { let msg = format!("Buffer ({nbytes}) not evenly divisible by typesize: {typesize}"); return Err(Error::Other(msg)); } let nchunks = unsafe { ffi::blosc2_schunk_append_buffer(*self.0.read(), data.as_ptr() as _, nbytes as _) }; if nchunks < 0 { return Err(Blosc2Error::from(nchunks as i32).into()); } Ok(nchunks as _) } /// Decompress a chunk, returning number of elements of `T` written to output buffer #[inline] pub fn decompress_chunk(&mut self, nchunk: usize, dst: &mut [T]) -> Result { let chunk = Chunk::from_schunk(self, nchunk)?; let info = chunk.info()?; if dst.len() * mem::size_of::() < info.nbytes as usize { let msg = format!( "Not large enough, need {} bytes but got buffer w/ {} bytes of storage", info.nbytes, dst.len() * mem::size_of::() ); return Err(msg.into()); } let ptr = dst.as_mut_ptr() as _; let size = unsafe { ffi::blosc2_schunk_decompress_chunk( *self.0.read(), nchunk as _, ptr, info.nbytes as _, ) }; if size < 0 { return Err(Blosc2Error::from(size).into()); } else if size == 0 { let msg = format!("Non-initialized error decompressing chunk '{}'", nchunk); return Err(msg.into()); } else { Ok((size / mem::size_of::() as i32) as _) } } #[inline] pub fn decompress_chunk_vec(&mut self, nchunk: usize) -> Result> { let chunk = Chunk::from_schunk(self, nchunk)?; chunk.decompress() } /// Set slice buffer pub fn set_slice_buffer(&self, start: usize, stop: usize, buf: &[u8]) -> Result<()> { if stop > self.len() { return Err(Error::from(format!( "`stop`: {} must be less than len: {}", stop, self.len(), ))); } if buf.len() % self.typesize() != 0 { return Err(Error::from( "Buffer is not evenly divisible by SChunk typesize", )); } let rc = unsafe { ffi::blosc2_schunk_set_slice_buffer( *self.0.write(), start as _, stop as _, buf.as_ptr() as *const _ as *mut _, ) }; if rc != 0 { return Err(Blosc2Error::from(rc).into()); } Ok(()) } /// Get uncompressed slice of data from start until stop. Returned as bytes, which /// can be transmuted/casted into the concrete item type. /// start/stop is by items, not by bytes pub fn get_slice_buffer(&self, start: usize, stop: usize) -> Result> { if stop > self.len() { return Err(Error::from(format!( "Out of bounds. `stop`={}, is more than length={}", stop, self.len() ))); } if stop <= start { return Err(Error::from("start must be less than stop")); } let nbytes = (stop - start) * self.typesize(); let mut buf = vec![0u8; nbytes]; let rc = unsafe { ffi::blosc2_schunk_get_slice_buffer( *self.0.read(), start as _, stop as _, buf.as_mut_ptr() as _, ) }; if rc != 0 { return Err(Blosc2Error::from(rc).into()); } Ok(buf) } /// Convenience method to `get_slice_buffer` which will transmute resulting bytes buffer into `Vec` for you. /// **NB** This will check T is same size as schunk's typesize so is _fairly_ safe. pub fn get_slice_buffer_as_type(&self, start: usize, stop: usize) -> Result> { if mem::size_of::() != self.typesize() { return Err(Error::from("Size of T does not match schunk typesize")); } let buf = self.get_slice_buffer(start, stop)?; Ok(unsafe { mem::transmute(buf) }) } pub fn get_chunk(&self, nchunk: usize) -> Result { let mut needs_free = true; let mut chunk = std::ptr::null_mut(); let nbytes = unsafe { ffi::blosc2_schunk_get_chunk( *self.0.read(), nchunk as _, &mut chunk as _, &mut needs_free, ) }; if nbytes < 0 { Err(Blosc2Error::from(nbytes).into()) } else { Ok(Chunk::new(chunk, needs_free)) } } /// Export this `SChunk` into a buffer pub fn into_vec(self) -> Result> { if self.is_empty() { return Ok(vec![]); } unsafe { ffi::blosc2_schunk_avoid_cframe_free(*self.0.read(), true) }; let mut needs_free = true; let mut ptr: *mut u8 = std::ptr::null_mut(); let len = unsafe { ffi::blosc2_schunk_to_buffer(*self.0.read(), &mut ptr, &mut needs_free) }; if len < 0 { return Err(Blosc2Error::from(len as i32).into()); } let mut buf = unsafe { Vec::from_raw_parts(ptr, len as _, len as _) }; if !needs_free { buf = buf.clone(); // Clone into new since blosc is about to free this one } Ok(buf) } /// Create a Schunk from an owned `Vec`. Data will be owned by the Schunk and released /// via normal Rust semantics. pub fn from_vec(buf: Vec) -> Result { let mut buf = buf; let schunk = unsafe { ffi::blosc2_schunk_from_buffer(buf.as_mut_ptr(), buf.len() as _, false) }; if schunk.is_null() { return Err(Error::from( "Failed to get schunk from buffer; might not be valid buffer for schunk", )); } unsafe { ffi::blosc2_schunk_avoid_cframe_free(schunk, true) }; mem::forget(buf); // blosc2 Ok(Self(Arc::new(RwLock::new(schunk)))) } // --- PROPERTIES --- /// Check if storage of Schunk is contiguous. pub fn is_contiguous(&self) -> bool { unsafe { (*(self.inner()).storage).contiguous } } /// Check typesize pub fn typesize(&self) -> usize { self.inner().typesize as _ } /// Compression ratio of the Schunk pub fn compression_ratio(&self) -> f32 { if self.inner().cbytes == 0 { return 0f32; } self.inner().nbytes as f32 / self.inner().cbytes as f32 } /// Number of chunks pub fn n_chunks(&self) -> usize { self.inner().nchunks as _ } /// Chunk shape pub fn chunk_shape(&self) -> usize { (self.inner().chunksize / self.inner().typesize) as _ } /// blocksize pub fn blocksize(&self) -> usize { self.inner().blocksize as _ } /// Count of uncompressed bytes pub fn nbytes(&self) -> usize { self.inner().nbytes as _ } /// Count of compressed bytes pub fn cbytes(&self) -> usize { self.inner().cbytes as _ } /// Path where the Schunk is stored, if file backed. pub fn path(&self) -> Option { let urlpath_ptr = unsafe { (*(self.inner().storage)).urlpath }; if urlpath_ptr.is_null() { return None; } let urlpath = unsafe { CStr::from_ptr(urlpath_ptr) }; urlpath.to_str().map(PathBuf::from).ok() } /// Returns under of elements in Schunk (nbytes / typesize) pub fn len(&self) -> usize { (self.inner().nbytes / self.inner().typesize as i64) as usize } pub fn is_empty(&self) -> bool { self.len() == 0 } } impl Drop for SChunk { fn drop(&mut self) { // drop if this is the only reference to pointer if Arc::strong_count(&self.0) == 1 && !(*self.0.read()).is_null() { unsafe { ffi::blosc2_schunk_free(*self.0.write()) }; } } } impl io::Write for SChunk { fn write(&mut self, buf: &[u8]) -> io::Result { self.append_buffer(buf)?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } /// struct only used for wrapping a mutable reference to a `SChunk` /// to support `std::io::Read` decoding for a SChunk. /// /// This isn't needed for encoding `std::io::Write` since we can directly /// write buffers into SChunk. However, for `Read`, we can't be certain the /// decompressed chunks will fit into the supplied `&mut [u8]` buffer provided /// during `Read::read`. So this struct exists only to hold those intermediate /// buffer and position variables and not clutter `SChunk` implementation. pub struct SChunkDecoder<'schunk> { pub(crate) schunk: &'schunk mut SChunk, pub(crate) buf: io::Cursor>, pub(crate) nchunk: usize, } impl<'schunk> SChunkDecoder<'schunk> { pub fn new(schunk: &'schunk mut SChunk) -> Self { Self { schunk, buf: io::Cursor::new(vec![]), nchunk: 0, } } } impl<'schunk> io::Read for SChunkDecoder<'schunk> { fn read(&mut self, buf: &mut [u8]) -> io::Result { // Cursor is at end of buffer, so we can refill if self.buf.position() as usize == self.buf.get_ref().len() { if self.nchunk >= self.schunk.n_chunks() { return Ok(0); } self.buf.get_mut().truncate(0); self.buf.set_position(0); // Get chunk and check if we can decompress directly into caller's buffer let chunk = Chunk::from_schunk(self.schunk, self.nchunk)?; let nbytes = chunk.info()?.nbytes(); if nbytes <= buf.len() { self.schunk.decompress_chunk(self.nchunk, buf)?; self.nchunk += 1; return Ok(nbytes); } else { self.buf.get_mut().resize(nbytes as _, 0u8); let nbytes_written: usize = self .schunk .decompress_chunk(self.nchunk, self.buf.get_mut().as_mut_slice())?; // These should always be equal, otherwise blosc2 gave the wrong expected // uncompressed size of this chunk. debug_assert_eq!(nbytes_written, nbytes); } self.nchunk += 1; } self.buf.read(buf) } } } /// Wrapper to [blosc2_cparams]. /// Compression parameters. /// /// A normal way to construct this is using `std::convert::From<&T>(val)` /// so it will create with default parameters and the correct `typesize`. /// /// Example /// ------- /// ``` /// use blosc2::CParams; /// let values = vec![0u8, 1, 2, 3]; /// let cparams = CParams::new::() /// .set_nthreads(2); // Optionally adjust default values /// ``` /// [blosc2_cparams]: blosc2_sys::blosc2_cparams pub struct CParams(ffi::blosc2_cparams); impl CParams { pub fn new() -> Self { Self::default().set_typesize::() } pub fn from_typesize(typesize: usize) -> Self { let mut cparams = Self::default(); cparams.0.typesize = typesize as _; cparams } pub(crate) fn into_inner(self) -> ffi::blosc2_cparams { self.0 } #[allow(dead_code)] pub(crate) fn inner_ref_mut(&mut self) -> &mut ffi::blosc2_cparams { &mut self.0 } /// Set codec, defaults to [Codec::BloscLz] /// /// [Codec::BloscLz]: crate::Codec::BloscLz pub fn set_codec(mut self, codec: Codec) -> Self { self.0.compcode = codec as _; self } /// Set clevel, defaults to [CLevel::Nine] /// /// [CLevel::Nine]: crate::CLevel::Nine pub fn set_clevel(mut self, clevel: CLevel) -> Self { self.0.clevel = clevel as _; self } /// Set filter, defaults to [Filter::Shuffle] /// /// [Filter::Shuffle]: crate::Filter::Shuffle pub fn set_filter(mut self, filter: Filter) -> Self { self.0.filters[ffi::BLOSC2_MAX_FILTERS as usize - 1] = filter as _; self } /// Set number of threads, defaults to 1 pub fn set_nthreads(mut self, n: usize) -> Self { self.0.nthreads = n as _; self } /// Get number of threads pub fn get_nthreads(&self) -> usize { self.0.nthreads as _ } /// Set the type size pub fn set_typesize(mut self) -> Self { self.0.typesize = mem::size_of::() as _; self } pub fn get_typesize(&self) -> usize { self.0.typesize as _ } } impl Default for CParams { #[inline] fn default() -> Self { let cparams = unsafe { ffi::blosc2_get_blosc2_cparams_defaults() }; Self(cparams) } } /// Create CParams from a reference to the type being compressed impl From<&T> for CParams { fn from(_: &T) -> Self { let mut cparams = CParams::default(); cparams.0.typesize = mem::size_of::() as _; cparams } } /// Wrapper to [blosc2_dparams]. /// Decompression parameters, normally constructed via `DParams::default()`. /// /// Example /// ------- /// ``` /// use blosc2::DParams; /// let dparams = DParams::default() /// .set_nthreads(2); // Optionally adjust default values /// ``` /// /// [blosc2_dparams]: blosc2_sys::blosc2_dparams pub struct DParams(pub(crate) ffi::blosc2_dparams); impl DParams { /// Set number of theads for decompression, defaults to 1 pub fn set_nthreads(mut self, n: usize) -> Self { self.0.nthreads = n as _; self } pub fn get_nthreads(&self) -> usize { self.0.nthreads as _ } } impl Default for DParams { #[inline] fn default() -> Self { let dparams = unsafe { ffi::blosc2_get_blosc2_dparams_defaults() }; Self(dparams) } } /// Wrapper to [blosc2_context]. /// Container struct for de/compression ops requiring context when used in multithreaded environments /// /// [blosc2_context]: blosc2_sys::blosc2_context #[derive(Clone)] pub struct Context(pub(crate) *mut ffi::blosc2_context); impl Context { /// Get the CParams from this context /// /// Example /// ------- /// ``` /// use blosc2::{Context, CParams}; /// /// let ctx = Context::from(CParams::default().set_typesize::()); /// assert_eq!(ctx.get_cparams().unwrap().get_typesize(), 8); /// ``` pub fn get_cparams(&self) -> Result { if self.0.is_null() { return Err("Context pointer is null".into()); } let mut cparams = CParams::default(); let rc = unsafe { ffi::blosc2_ctx_get_cparams(self.0, &mut cparams.0) }; if rc < 0 { return Err(Blosc2Error::from(rc).into()); } Ok(cparams) } /// Get the DParams from this context /// /// Example /// ------- /// ``` /// use blosc2::{Context, DParams}; /// /// let ctx = Context::from(DParams::default().set_nthreads(12)); /// assert_eq!(ctx.get_dparams().unwrap().get_nthreads(), 12); /// ``` pub fn get_dparams(&self) -> Result { if self.0.is_null() { return Err("Context pointer is null".into()); } let mut dparams = DParams::default(); let rc = unsafe { ffi::blosc2_ctx_get_dparams(self.0, &mut dparams.0) }; if rc < 0 { return Err(Blosc2Error::from(rc).into()); } Ok(dparams) } } impl From for Context { fn from(dparams: DParams) -> Self { Self(unsafe { ffi::blosc2_create_dctx(dparams.0) }) } } impl From for Context { fn from(cparams: CParams) -> Self { Self(unsafe { ffi::blosc2_create_cctx(cparams.0) }) } } impl Default for Context { fn default() -> Self { let ctx = unsafe { ffi::blosc2_create_cctx(CParams::default().into_inner()) }; Self(ctx) } } impl Drop for Context { fn drop(&mut self) { if !self.0.is_null() { unsafe { ffi::blosc2_free_ctx(self.0) }; } } } /// Info about a compressed buffer /// Normal construction via `CompressedBufferInfo::try_from(&[u8])?` #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct CompressedBufferInfo { /// Number of bytes decompressed nbytes: usize, /// Number of bytes to be read from compressed buffer cbytes: usize, /// Used internally by blosc2 when compressing the blocks, exposed here for completion. /// You probably won't need it. blocksize: usize, } impl CompressedBufferInfo { pub fn nbytes(&self) -> usize { self.nbytes } pub fn cbytes(&self) -> usize { self.cbytes } pub fn blocksize(&self) -> usize { self.blocksize } } impl TryFrom<&[T]> for CompressedBufferInfo { type Error = Error; #[inline] fn try_from(buf: &[T]) -> Result { let mut nbytes = 0i32; let mut cbytes = 0i32; let mut blocksize = 0i32; let code = unsafe { ffi::blosc2_cbuffer_sizes( buf.as_ptr() as *const c_void, &mut nbytes as *mut _, &mut cbytes as *mut _, &mut blocksize as *mut _, ) }; if code < 0 { return Err(Blosc2Error::from(code).into()); } Ok(CompressedBufferInfo { nbytes: nbytes as _, cbytes: cbytes as _, blocksize: blocksize as _, }) } } impl TryFrom<*const c_void> for CompressedBufferInfo { type Error = Error; #[inline] fn try_from(ptr: *const c_void) -> Result { let mut nbytes = 0i32; let mut cbytes = 0i32; let mut blocksize = 0i32; let code = unsafe { ffi::blosc2_cbuffer_sizes( ptr, &mut nbytes as *mut _, &mut cbytes as *mut _, &mut blocksize as *mut _, ) }; if code < 0 { return Err(Blosc2Error::from(code).into()); } Ok(CompressedBufferInfo { nbytes: nbytes as _, cbytes: cbytes as _, blocksize: blocksize as _, }) } } /// Retrieve a number of elements from a `Chunk` /// /// Example /// ------- /// ``` /// use blosc2::{getitems, compress}; /// /// let chunk = compress(&vec![0u32, 1, 2, 3, 4], None, None, None, None).unwrap(); /// /// let offset = 1; /// let n_items = 2; /// let items = getitems::(&chunk, offset, n_items).unwrap(); /// assert_eq!(items, vec![1u32, 2]); /// ``` #[inline] pub fn getitems(src: &[u8], offset: usize, n_items: usize) -> Result> { let mut dst = Vec::with_capacity(n_items); let nbytes = unsafe { ffi::blosc2_getitem( src.as_ptr() as *const c_void, src.len() as _, offset as _, n_items as _, dst.as_mut_ptr() as *mut c_void, (n_items * mem::size_of::()) as i32, ) }; if nbytes < 0 { return Err(Blosc2Error::from(nbytes).into()); } unsafe { dst.set_len(nbytes as usize / mem::size_of::()) }; Ok(dst) } /// Get a list of supported compressors in this build #[inline] pub fn list_compressors() -> Result> { let names = unsafe { let ptr = ffi::blosc2_list_compressors(); CStr::from_ptr(ptr) .to_str() .map(ToString::to_string) .map_err(|e| Error::Other(e.to_string())) }?; let mut compressors = vec![]; for name in names.split(',') { compressors.push(Codec::try_from(name)?); } Ok(compressors) } /// Context interface to compression, does not require call to init/destroy. For /// use in multithreaded applications #[inline] pub fn compress_ctx(src: &[T], ctx: &mut Context) -> Result> { if src.is_empty() { return Ok(vec![]); } let mut dst = vec![0u8; max_compress_len(src, ctx.get_cparams().ok().map(|c| c.get_typesize()))]; let size = compress_into_ctx(src, &mut dst, ctx)?; if dst.len() > size { dst.truncate(size as _); } Ok(dst) } #[inline] pub fn compress_into_ctx(src: &[T], dst: &mut [u8], ctx: &mut Context) -> Result { if src.is_empty() { return Ok(0); } let size = unsafe { ffi::blosc2_compress_ctx( ctx.0, src.as_ptr() as *const c_void, (src.len() * ctx.get_cparams()?.get_typesize()) as _, dst.as_mut_ptr() as *mut c_void, dst.len() as _, ) }; if size == 0 { return Err(format!("Buffer is incompressible").into()); } else if size < 0 { return Err(Blosc2Error::from(size).into()); } Ok(size as _) } /// Return the max size a compressed buffer needs to be to hold `src` #[inline(always)] pub fn max_compress_len(src: &[T], typesize: Option) -> usize { (src.len() * typesize.unwrap_or_else(|| mem::size_of::())) + ffi::BLOSC2_MAX_OVERHEAD as usize } pub fn max_compress_len_bytes(len_bytes: usize) -> usize { len_bytes + ffi::BLOSC2_MAX_OVERHEAD as usize } #[inline] pub fn compress( src: &[T], typesize: Option, clevel: Option, filter: Option, codec: Option, ) -> Result> { if src.is_empty() { return Ok(vec![]); } let mut dst = Vec::with_capacity(max_compress_len(src, typesize)); let typesize = typesize.unwrap_or_else(|| mem::size_of::()); set_compressor(codec.unwrap_or_default())?; // If input is bytes, but typesize is >1 then we use src len directly // since blosc2_compress want's the length in bytes let multiplier = (&src[0] as &dyn std::any::Any) .downcast_ref::() .map(|_| 1) .unwrap_or(typesize); let n_bytes = unsafe { ffi::blosc2_compress( clevel.unwrap_or_default() as _, filter.unwrap_or_default() as _, typesize as _, src.as_ptr() as *const c_void, (src.len() * multiplier) as _, dst.as_mut_ptr() as *mut c_void, dst.capacity() as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } else if n_bytes == 0 { return Err("Data is not compressable.".into()); } unsafe { dst.set_len(n_bytes as _) }; Ok(dst) } #[inline] pub fn compress_into( src: &[T], dst: &mut [u8], typesize: Option, clevel: Option, filter: Option, codec: Option, ) -> Result { if src.is_empty() { return Ok(0); } let typesize = typesize.unwrap_or_else(|| mem::size_of::()); set_compressor(codec.unwrap_or_default())?; // If input is bytes, but typesize is >1 then we use src len directly // since blosc2_compress want's the length in bytes let multiplier = (&src[0] as &dyn std::any::Any) .downcast_ref::() .map(|_| 1) .unwrap_or(typesize); let n_bytes = unsafe { ffi::blosc2_compress( clevel.unwrap_or_default() as _, filter.unwrap_or_default() as _, typesize as _, src.as_ptr() as *const c_void, (src.len() * multiplier) as _, dst.as_mut_ptr() as *mut c_void, dst.len() as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } else if n_bytes == 0 { return Err("Data is not compressable.".into()); } Ok(n_bytes as _) } #[inline] pub fn decompress_ctx(src: &[u8], ctx: &mut Context) -> Result> { if src.is_empty() { return Ok(vec![]); } let info = CompressedBufferInfo::try_from(src)?; let n_elements = info.nbytes as usize / mem::size_of::(); let mut dst = Vec::with_capacity(n_elements); let n_bytes = unsafe { ffi::blosc2_decompress_ctx( ctx.0, src.as_ptr() as *const c_void, src.len() as i32, dst.as_mut_ptr() as *mut c_void, info.nbytes as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } debug_assert_eq!(n_bytes as usize, info.nbytes); unsafe { dst.set_len(n_elements) }; Ok(dst) } #[inline] pub fn decompress_into_ctx(src: &[T], dst: &mut [T], ctx: &mut Context) -> Result { if src.is_empty() { return Ok(0); } let info = CompressedBufferInfo::try_from(src)?; let n_bytes = unsafe { ffi::blosc2_decompress_ctx( ctx.0, src.as_ptr() as *const c_void, src.len() as i32, dst.as_mut_ptr() as *mut c_void, info.nbytes as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } debug_assert_eq!(n_bytes as usize, info.nbytes); Ok(n_bytes as _) } /// Get the number of elements `T` in the compressed chunk #[inline] pub fn len(src: &[u8]) -> Result { let info = CompressedBufferInfo::try_from(src)?; Ok(info.nbytes() / mem::size_of::()) } #[inline] pub fn decompress(src: &[u8]) -> Result> { if src.is_empty() { return Ok(vec![]); } // blosc2 plays by bytes, we'll go by however many bytes per element // to set the vec length in actual elements let info = CompressedBufferInfo::try_from(src)?; let n_elements = info.nbytes as usize / mem::size_of::(); let mut dst = Vec::with_capacity(n_elements); let n_bytes = unsafe { ffi::blosc2_decompress( src.as_ptr() as *const c_void, src.len() as i32, dst.as_mut_ptr() as *mut c_void, info.nbytes as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } debug_assert_eq!(n_bytes as usize, info.nbytes); unsafe { dst.set_len(n_elements) }; Ok(dst) } #[inline] pub fn decompress_into(src: &[u8], dst: &mut [T]) -> Result { if src.is_empty() { return Ok(0); } let info = CompressedBufferInfo::try_from(src)?; let n_bytes = unsafe { ffi::blosc2_decompress( src.as_ptr() as *const c_void, src.len() as i32, dst.as_mut_ptr() as *mut c_void, info.nbytes as _, ) }; if n_bytes < 0 { return Err(Blosc2Error::from(n_bytes).into()); } debug_assert_eq!(n_bytes as usize, info.nbytes); Ok(n_bytes as _) } #[inline] pub fn set_compressor(codec: Codec) -> Result<()> { let codec_name = codec.to_name_cstring()?; let rc = unsafe { ffi::blosc1_set_compressor(codec_name.as_ptr()) }; if rc < 0 { Err(Blosc2Error::from(rc).into()) } else { Ok(()) } } pub fn set_nthreads(nthreads: usize) -> usize { let n = unsafe { ffi::blosc2_set_nthreads(nthreads as _) }; n as _ } pub fn get_nthreads() -> usize { unsafe { ffi::blosc2_get_nthreads() as _ } } /// Get the version for a given Codec. pub fn get_complib_info(codec: Codec) -> Result { let mut compname = std::ptr::null(); let mut complib = std::ptr::null_mut(); let mut version = std::ptr::null_mut(); if unsafe { ffi::blosc2_compcode_to_compname(codec as i32, &mut compname) } == -1 { return Err("Codec not recognized".into()); } if unsafe { ffi::blosc2_get_complib_info(compname as _, &mut complib, &mut version) } == -1 { return Err("Codec not supported".into()); } let info = unsafe { format!( "{}: {}", CString::from_raw(complib) .into_string() .map_err(|e| e.to_string())?, CString::from_raw(version) .into_string() .map_err(|e| e.to_string())? ) }; Ok(info) } /// Get the Blosc2 version string pub fn get_version_string() -> Result { CStr::from_bytes_with_nul(ffi::BLOSC2_VERSION_STRING) .map_err(|e| e.to_string())? .to_str() .map_err(|e| e.to_string().into()) .map(|s| s.to_string()) } /// Call before using blosc2, unless using specific ctx de/compression variants /// This is a safe wrapper to `blosc2_init` where a global `Arc>` is used to track /// if blosc2 has already been initialized. For fine grained control use `init_unsafe` / `destroy_unsafe` pub fn init() { let initd = BLOSC2_INIT_FLAG .get_or_init(|| Arc::new(Mutex::new(false))) .clone(); let mut guard = initd.lock(); if !*guard { unsafe { init_unsafe() }; *guard = true; } } /// Call before using blosc2, unless using specific ctx de/compression variants /// For a safe interface managing the singleton nature of this call, use `init`/`destroy` functions. pub unsafe fn init_unsafe() { unsafe { ffi::blosc2_init() } } /// Call at end of using blosc2 library, unless you've never called `blosc2_init` /// This is a safe wrapper to `blosc2_destroy` where a global `Arc>` is used to track /// if blosc2 has already been destroyed. For fine grained control use `init_unsafe` / `destroy_unsafe` pub fn destroy() { let initd = BLOSC2_INIT_FLAG .get_or_init(|| Arc::new(Mutex::new(false))) .clone(); let mut guard = initd.lock(); if *guard { unsafe { destroy_unsafe() }; *guard = false; } } /// Call at end of using blosc2 library, unless you've never called `blosc2_init` /// For a safe interface managing the singleton nature of this call, use `init`/`destroy` functions. pub unsafe fn destroy_unsafe() { unsafe { ffi::blosc2_destroy() }; } /// Singleton struct for initializing blosc2 and auto destroying it when going out of scope. /// **Note**: if you create more than one of these, the *last* one dropped will cause a call to `blosc2_destroy` pub struct Blosc2Guard; impl Blosc2Guard { /// Get or create the blosc2 initialization guard. If blosc2's init has already been called this /// will return the existing singleton otherwise will call init and return the singleton. pub fn get_or_init() -> Arc { init(); BLOSC2_GUARD.get_or_init(|| Arc::new(Self {})).clone() } } impl Drop for Blosc2Guard { fn drop(&mut self) { destroy(); } } /// Free possible memory temporaries and thread resources. Use this /// when you are not going to use Blosc for a long while. /// A 0 if succeeds, in case of problems releasing the resources, /// it returns a negative number. pub fn free_resources() -> Result<()> { let ret = unsafe { ffi::blosc2_free_resources() }; if ret != 0 { Err(Error::Blosc2(Blosc2Error::from(ret))) } else { Ok(()) } } #[cfg(test)] mod tests { use ctor::{ctor, dtor}; use std::io::Cursor; use super::*; #[ctor] fn blosc2_init() { init(); } #[dtor] fn blosc2_destory() { destroy(); } #[test] fn test_compress_ctx() -> Result<()> { let input = b"some data"; let compressed = compress_ctx(input, &mut Context::from(CParams::from(&input[0])))?; let decompressed = decompress(&compressed)?; assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_compress_into_ctx() -> Result<()> { let input = b"some data"; let mut compressed = vec![0u8; 100]; let n_bytes = compress_into_ctx( input, &mut compressed, &mut Context::from(CParams::from(&input[0])), )?; let decompressed = decompress(&compressed[..n_bytes])?; assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_decompress_ctx() -> Result<()> { let input = b"some data"; let compressed = compress(input, None, None, None, None)?; let decompressed = decompress_ctx(&compressed, &mut Context::from(DParams::default()))?; assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_decompress_into_ctx() -> Result<()> { let input = b"some data"; let compressed = compress(input, None, None, None, None)?; let mut decompressed = vec![0u8; input.len()]; let n_bytes = decompress_into_ctx( &compressed, &mut decompressed, &mut Context::from(DParams::default()), )?; assert_eq!(n_bytes, input.len()); assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_basic_roundtrip() -> Result<()> { let input = b"some data"; let compressed = compress(input, None, None, None, None)?; let decompressed = decompress(&compressed)?; assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_basic_roundtrip_into() -> Result<()> { let input = b"some data"; let mut compressed = vec![0u8; 100]; let n_bytes = compress_into(input, &mut compressed, None, None, None, None)?; let mut decompressed = vec![0u8; input.len()]; let n_out = decompress_into(&compressed[..n_bytes], &mut decompressed)?; assert_eq!(n_out, input.len()); assert_eq!(input, decompressed.as_slice()); Ok(()) } #[test] fn test_schunk_basic() -> Result<()> { let input = b"some data"; let storage = schunk::Storage::default() .set_contiguous(true) .set_cparams(CParams::from(&input[0])) .set_dparams(DParams::default()); let mut schunk = schunk::SChunk::new(storage); assert!(schunk.is_contiguous()); assert_eq!(schunk.typesize(), 1); assert!(schunk.path().is_none()); let mut decompressed = vec![0u8; input.len()]; let n = schunk.append_buffer(input)?; schunk.decompress_chunk(n - 1, &mut decompressed)?; assert_eq!(input, decompressed.as_slice()); { // ensure clone then drop doesn't free the schunk ptr, original still needs is let _cloned = schunk.clone(); } assert_eq!(schunk.n_chunks(), 1); // Reconstruct thru vec let v = schunk.into_vec()?; schunk = schunk::SChunk::from_vec(v)?; assert_eq!(schunk.n_chunks(), 1); Ok(()) } #[test] fn test_schunk_thread_shared() -> Result<()> { let input = b"some data"; let storage = schunk::Storage::default() .set_contiguous(true) .set_cparams(CParams::from(&input[0])) .set_dparams(DParams::default()); let mut schunk = schunk::SChunk::new(storage); schunk.append_buffer(input)?; let mut schunk2 = schunk.clone(); std::thread::spawn(move || { assert_eq!(schunk2.n_chunks(), 1); schunk2.append_buffer(b"more data").unwrap(); }) .join() .unwrap(); assert_eq!(schunk.n_chunks(), 2); assert_eq!( b"some data", schunk.decompress_chunk_vec(0).unwrap().as_slice() ); assert_eq!( b"more data", schunk.decompress_chunk_vec(1).unwrap().as_slice() ); Ok(()) } #[cfg(not(target_os = "windows"))] #[test] fn test_schunk_write() -> Result<()> { let input = std::iter::repeat(b"some data") .take(BUFSIZE) .flat_map(|v| v.to_vec()) .collect::>(); let storage = schunk::Storage::default() .set_contiguous(true) .set_cparams(CParams::from(&input[0])) .set_dparams(DParams::default()); let mut schunk = schunk::SChunk::new(storage); let nbytes = std::io::copy(&mut Cursor::new(input.clone()), &mut schunk) .map_err(|e| Error::Other(e.to_string()))?; assert_eq!(nbytes as usize, input.len()); let ratio = schunk.compression_ratio(); assert!(84. < ratio); assert!(86. > ratio); let mut uncompressed = vec![]; let mut decoder = schunk::SChunkDecoder::new(&mut schunk); let n = std::io::copy(&mut decoder, &mut uncompressed).unwrap(); assert_eq!(input, uncompressed.as_slice()); assert_eq!(n as usize, input.len()); Ok(()) } #[cfg(not(target_os = "windows"))] #[test] fn test_get_version_string() -> Result<()> { let version = get_version_string()?; assert_eq!(&version, "2.15.1"); Ok(()) } #[cfg(not(target_os = "windows"))] #[test] fn test_get_complib_version_string() -> Result<()> { let info = get_complib_info(Codec::BloscLz)?; assert_eq!(&info, "BloscLZ: 2.5.3"); Ok(()) } #[test] fn test_list_compressors() { let compressors = list_compressors().unwrap(); for compressor in &[ Codec::BloscLz, Codec::LZ4, Codec::LZ4HC, Codec::ZLIB, Codec::ZSTD, ] { assert!(compressors.contains(compressor)); } } }