diff --git a/.github/workflows/cargo-build.yml b/.github/workflows/cargo-build.yml index 38600635..7b1a6cd9 100644 --- a/.github/workflows/cargo-build.yml +++ b/.github/workflows/cargo-build.yml @@ -73,16 +73,10 @@ jobs: run: | make cargo-b-release - - name: cargo-build-release-tokio - run: | - make cargo-build-release-tokio - - name: cargo-build-release-async-std run: | make cargo-build-release-async-std - - - name: Run tests run: source "$HOME/.cargo/env" && cargo test --verbose diff --git a/Cargo.lock b/Cargo.lock index 500f67a3..41c8111b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,13 +157,13 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.2.1", + "async-io 2.2.2", "async-lock 3.2.0", "blocking", "futures-lite 2.1.0", @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7" dependencies = [ "async-lock 3.2.0", "cfg-if", @@ -203,7 +203,7 @@ dependencies = [ "futures-lite 2.1.0", "parking", "polling 3.3.1", - "rustix 0.38.26", + "rustix 0.38.28", "slab", "tracing", "windows-sys 0.52.0", @@ -242,7 +242,7 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.26", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -252,13 +252,13 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" dependencies = [ - "async-io 2.2.1", + "async-io 2.2.2", "async-lock 2.8.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.26", + "rustix 0.38.28", "signal-hook-registry", "slab", "windows-sys 0.48.0", @@ -306,7 +306,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -867,7 +867,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1183,7 +1183,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1352,12 +1352,13 @@ dependencies = [ "sha2", "sluice", "snow", + "tempfile", "test-log", "time", "tokio", "tracing", "tracing-subscriber", - "wasi 0.10.0+wasi-snapshot-preview1", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -1437,9 +1438,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1641,9 +1642,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" @@ -1671,9 +1672,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libgit2-sys" @@ -1935,9 +1936,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -2130,7 +2131,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite 0.2.13", - "rustix 0.38.26", + "rustix 0.38.28", "tracing", "windows-sys 0.52.0", ] @@ -2534,9 +2535,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", @@ -2547,9 +2548,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", @@ -2578,9 +2579,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2666,7 +2667,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2853,9 +2854,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -2910,7 +2911,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall", - "rustix 0.38.26", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -2925,13 +2926,23 @@ dependencies = [ [[package]] name = "test-log" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66edd6b6cd810743c0c71e1d085e92b01ce6a72782032e3f794c8284fe4bcdd" +checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b" +dependencies = [ + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2957,7 +2968,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2972,12 +2983,11 @@ dependencies = [ [[package]] name = "time" -version = "0.1.45" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -3008,9 +3018,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -3032,7 +3042,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3111,7 +3121,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3161,9 +3171,9 @@ checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" @@ -3202,9 +3212,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -3339,9 +3349,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasi" @@ -3370,7 +3380,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -3404,7 +3414,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 24ebc93e..e74bf707 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ tracing = "0.1" pretty-hash = "0.4" futures-timer = "3" futures-lite = "1" -hypercore = { version = "0.12", default-features = false } +hypercore = { version = "0.12", default-features = false, features = ["async-std", "cache", "js_interop_tests", "moka", "sparse"] } sha2 = "0.10" curve25519-dalek = "4" crypto_secretstream = "0.2" @@ -61,14 +61,26 @@ nostr-sdk = "0.24.0" wasi = { version = "0.10.0", features = ["std"] } oorandom = "11.1.3" +##$ cargo add random-access-disk +## Updating crates.io index +## Adding random-access-disk v3.0.0 to dependencies. +## Features: +## + async-std +## + libc +## + sparse +## - tokio +## NOTE:We favor async-std in this build config + +random-access-storage = "5.0.0" +random-access-disk = { version = "3.0.0", default-features = false } +random-access-memory = "3.0.0" +tempfile = "3.8.1" + [dev-dependencies] async-std = { version = "1.12.0", features = ["attributes", "unstable"] } async-compat = "0.2.1" tokio = { version = "1.27.0", features = ["macros", "net", "process", "rt", "rt-multi-thread", "sync", "time"] } env_logger = "0.7.1" -random-access-storage = "5.0.0" -random-access-disk = { version = "3.0.0", default-features = false } -random-access-memory = "3.0.0" anyhow = "1.0.28" instant = "0.1" criterion = { version = "0.4", features = ["async_std"] } diff --git a/GNUmakefile b/GNUmakefile index 9dfad5d4..b4e5186d 100755 --- a/GNUmakefile +++ b/GNUmakefile @@ -95,20 +95,26 @@ export RUSTC RUSTUP:=$(shell which rustup) export RUSTUP +FEATURES:=\ +async-std\ + +RELEASE:=\ +stable\ + + -: @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?##/ {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) help:## help @sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /' -rustup-install:rustup-install-stable## rustup-install -rustup-install-stable:## rustup-install-stable +rustup-install:rustup-install-$(RELEASE)## rustup-install +rustup-install-$(RELEASE):## rustup-install-$(RELEASE) ## install rustup sequence - $(shell echo which rustup) || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --default-toolchain stable --profile default && . "$(HOME)/.cargo/env" - $(shell echo which rustup) && rustup default stable -rustup-install-nightly:## rustup-install-nightly -## install rustup sequence - $(shell echo which rustup) || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --default-toolchain nightly --profile default && . "$(HOME)/.cargo/env" - $(shell echo which rustup) && rustup default nightly - + $(shell echo which rustup) || \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ + sh -s -- -y --no-modify-path \ + --default-toolchain $(RELEASE) \ + --profile default && . "$(HOME)/.cargo/env" + $(shell echo which rustup) && rustup default $(RELEASE) cargo-b:## cargo-b [ -x "$(shell command -v $(RUSTUP))" ] || $(MAKE) rustup-install-stable diff --git a/cargo.mk b/cargo.mk index 166c14e7..79c7f686 100755 --- a/cargo.mk +++ b/cargo.mk @@ -3,8 +3,8 @@ cargo-help:### cargo-help @awk 'BEGIN {FS = ":.*?###"} /^[a-zA-Z_-]+:.*?###/ {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) -cargo-bt:cargo-build-tokio### cargo-bt -cargo-build-tokio:### cargo-build-tokio +cargo-bt:cargo-build-tokio +cargo-build-tokio: ## make cargo-build-tokio q=true @. $(HOME)/.cargo/env @RUST_BACKTRACE=all cargo b $(QUIET) --no-default-features --features tokio @@ -20,10 +20,10 @@ cargo-install:### cargo install --path . #@cargo install --path $(PWD) @cargo install --locked --path $(PWD) -cargo-br-tokio:cargo-build-release-tokio### cargo-br-tokio +cargo-br-tokio:cargo-build-release-tokio ## make cargo-br-tokio q=true -cargo-build-release-tokio:### cargo-build-release-tokio +cargo-build-release-tokio: ## make cargo-build-release-tokio q=true @. $(HOME)/.cargo/env @cargo b $(QUIET) --profile=$(PROFILE) --no-default-features --features tokio @@ -41,7 +41,7 @@ cargo-check:### cargo-check @. $(HOME)/.cargo/env @cargo c -cargo-check-tokio:### cargo-check-tokio +cargo-check-tokio: ## cargo c --no-default-features --features tokio @. $(HOME)/.cargo/env @cargo check --no-default-features --features tokio @@ -56,28 +56,27 @@ cargo-bench:### cargo-bench @. $(HOME)/.cargo/env @cargo bench -cargo-tt:cargo-test-tokio### cargo-tt -cargo-test-tokio:### cargo-test-tokio -## cargo tt +cargo-t-tok:cargo-test-tokio +cargo-test-tokio: +## cargo-t-tok @. $(HOME)/.cargo/env && cargo test --no-default-features --features tokio -cargo-ts:cargo-test-async-std### cargo-ts +cargo-t-async:cargo-test-async-std### cargo-t-async cargo-test-async-std:### cargo-test-async-std -## cargo ts +## cargo t-async @. $(HOME)/.cargo/env && cargo test --no-default-features --features async-std cargo-jits:### cargo-jits ## cargo-jits @. $(HOME)/.cargo/env && $(MAKE) cargo-t-jit-tokio cargo-t-jit-as -cargo-t-jit-tokio:cargo-test-js-interop-tokio### cargo-test-jit-tokio +cargo-t-jit-tokio:cargo-test-js-interop-tokio cargo-test-js-interop-tokio: @. $(HOME)/.cargo/env && cargo test --no-default-features --features js_interop_tests,tokio cargo-t-jit-as:cargo-test-js-interop-async-std### cargo-test-jit-as cargo-test-js-interop-async-std: @. $(HOME)/.cargo/env && cargo test --no-default-features --features js_interop_tests,async-std - cargo-test-benches:### cargo-test-benches cargo test --benches diff --git a/examples/disk.rs b/examples/disk.rs new file mode 100755 index 00000000..99990897 --- /dev/null +++ b/examples/disk.rs @@ -0,0 +1,88 @@ +#[cfg(feature = "async-std")] +use async_std::main as async_main; +use hypercore::{HypercoreBuilder, HypercoreError, Storage}; +use tempfile::Builder; +#[cfg(feature = "tokio")] +use tokio::main as async_main; + +/// Example about using an in-memory hypercore. +#[async_main] +async fn main() { + // For the purposes of this example, first create a + // temporary directory to hold hypercore. + let dir = Builder::new() + .prefix("examples_disk") + .tempdir() + .unwrap() + .into_path(); + + // Create a disk storage, overwriting existing values. + let overwrite = true; + let storage = Storage::new_disk(&dir, overwrite) + .await + .expect("Could not create disk storage"); + + // Build a new disk hypercore + let mut hypercore = HypercoreBuilder::new(storage) + .build() + .await + .expect("Could not create disk hypercore"); + + // Append values to the hypercore + hypercore.append(b"Hello, ").await.unwrap(); + hypercore.append(b"from ").await.unwrap(); + + // Close hypercore + drop(hypercore); + + // Open hypercore again from same directory, not + // overwriting. + let overwrite = false; + let storage = Storage::new_disk(&dir, overwrite) + .await + .expect("Could not open existing disk storage"); + let mut hypercore = HypercoreBuilder::new(storage) + .open(true) + .build() + .await + .expect("Could not open disk hypercore"); + + // Append new values to the hypercore + hypercore.append(b"disk hypercore!").await.unwrap(); + + // Add three values and clear the first two + let batch: &[&[u8]] = &[ + b"first value to clear", + b"second value to clear", + b"third value to keep", + ]; + let new_length = hypercore.append_batch(batch).await.unwrap().length; + hypercore + .clear(new_length - 3, new_length - 1) + .await + .unwrap(); + + // The two values return None, but the last one returns correctly + assert!(hypercore.get(3).await.unwrap().is_none()); + assert!(hypercore.get(4).await.unwrap().is_none()); + assert_eq!( + hypercore.get(5).await.unwrap().unwrap(), + b"third value to keep" + ); + + // Print the first three values, converting binary back to string + println!( + "{}{}{}", + format_res(hypercore.get(0).await), + format_res(hypercore.get(1).await), + format_res(hypercore.get(2).await) + ); // prints "Hello, from disk hypercore!" +} + +fn format_res(res: Result>, HypercoreError>) -> String { + match res { + Ok(Some(bytes)) => String::from_utf8(bytes).expect("Shouldn't fail in example"), + Ok(None) => "Got None in feed".to_string(), + Err(e) => format!("Error getting value from feed, reason = {e:?}"), + } +} diff --git a/vendor/random-access-disk/.cargo-checksum.json b/vendor/random-access-disk/.cargo-checksum.json new file mode 100644 index 00000000..37e453f5 --- /dev/null +++ b/vendor/random-access-disk/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CERTIFICATE":"53a0a460f8eccb279580aa16013c5f98936eba73554d267632f5ea83d8e890b1","CHANGELOG.md":"6f0b92fa275c7be51128871ac654117550d87bd22c1625d749615219f0a8001c","Cargo.toml":"149837e57a711a21d300309abc64a5facf48d40fc956e8fd0dbdd5787780103a","LICENSE-APACHE":"40b135370517318ee023f4553b49453ab716f4277ccc7801beb3a44ec481c9fb","LICENSE-MIT":"a06326997c80661a79a99f66af7417f3420640323952c92afae69d5a4b7537ee","README.md":"0217852c66807c2141f2edca78d85c3a813aa05d2d97617595f75d837b6daf81","benches/sync.rs":"acfd7eae0ca6fb9b112c54412bc39c3a0462c806bc1fe48d506d951135275398","rustfmt.toml":"bd5701c9a978dcf1d7663447ca8aca21019a06cfe21f67863f459f80b8136f1a","src/default.rs":"703e0143e6403d5ae5513970f6ec0679b1e5db456674039d1efc6bc610976daf","src/lib.rs":"d5d36cd73bb0446e808ab119cd62212944ff119ad9c5026da9de33586e964094","src/unix.rs":"6bfe9b49960ff19c68f1d6923cedc3fd1c77083a12ac00047ab36660c61f94fa","src/windows.rs":"f60506ace025fc9c9b5e5eefb312773b9e63787bad6c373b0cae3a9b433779a2","tests/model.rs":"fd477a10b10e54512de55423b5dc8cb3a89c2207f5caf3941e2597e3d336c348","tests/regression.rs":"4167225be4010b41548ce53ecb69e219b17b52139925ca07aa4e07b0f821babc","tests/test.rs":"13beba957755a55061b4296cd33140991dca15848bcc62aef19513c93010df01"},"package":"cafc2a3edd8ab8da5389cfdb3ffcf4e0b67c9a1dc8456ddb2511f4c848b524f5"} \ No newline at end of file diff --git a/vendor/random-access-disk/CERTIFICATE b/vendor/random-access-disk/CERTIFICATE new file mode 100644 index 00000000..8201f992 --- /dev/null +++ b/vendor/random-access-disk/CERTIFICATE @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/random-access-disk/CHANGELOG.md b/vendor/random-access-disk/CHANGELOG.md new file mode 100644 index 00000000..26e0e4bb --- /dev/null +++ b/vendor/random-access-disk/CHANGELOG.md @@ -0,0 +1,147 @@ +## 2020-03-03, Version 2.0.0 +### Commits +- [[`e480856d06`](https://github.com/datrs/random-access-disk/commit/e480856d06af1357f33ef7bf826373c169df83d2)] (cargo-release) version 2.0.0 (Bruno Tavares) +- [[`b0f1507868`](https://github.com/datrs/random-access-disk/commit/b0f15078689fbfd379aa249ff45bf28be54f2249)] Implement async API for random-access-storage (#37) (Bruno Tavares) +- [[`4eb18f5045`](https://github.com/datrs/random-access-disk/commit/4eb18f50458df30da747cbef7380704d2c7791d1)] Update changelog (Bruno Tavares) + +### Stats +```diff + CHANGELOG.md | 16 ++++- + Cargo.toml | 7 +- + README.md | 9 +-- + benches/sync.rs | 81 ++++++++++++--------- + src/lib.rs | 74 ++++++++++++------- + tests/model.rs | 54 +++++++------- + tests/regression.rs | 20 ++--- + tests/test.rs | 203 +++++++++++++++++++++++++++++------------------------ + 8 files changed, 271 insertions(+), 193 deletions(-) +``` + + +## 2020-03-03, Version 1.1.0 +### Commits +- [[`7063f6fa47`](https://github.com/datrs/random-access-disk/commit/7063f6fa47dc7689e1d44055aa594845345f890f)] (cargo-release) version 1.1.0 (Bruno Tavares) +- [[`218aab2629`](https://github.com/datrs/random-access-disk/commit/218aab2629ce76308c946c62b61078b749100c53)] From Failure into std::error::Error (#36) (Bruno Tavares) +- [[`a8bfebeeb7`](https://github.com/datrs/random-access-disk/commit/a8bfebeeb7edda672783aeb9ab5fa9f9555e4b74)] Bump dependencies and fix travis (#35) (Bruno Tavares) + +### Stats +```diff + .travis.yml | 8 +++++--- + CHANGELOG.md | 26 ++++++++++++++++++++++++++ + Cargo.toml | 8 ++++---- + src/lib.rs | 24 +++++++++++++----------- + 4 files changed, 48 insertions(+), 18 deletions(-) +``` + + +## 2020-02-02, Version 1.0.0 +### Commits +- [[`3de8d37a0c`](https://github.com/datrs/random-access-disk/commit/3de8d37a0c33bc15874de8870734bbdd07a8b24c)] 1.0.0 (substack) +- [[`2fca3428a6`](https://github.com/datrs/random-access-disk/commit/2fca3428a6ca6e484c5b31c8b62422553641731e)] Merge pull request #28 from bltavares/bump-deps (Szabolcs Berecz) +- [[`bebe8b4a2c`](https://github.com/datrs/random-access-disk/commit/bebe8b4a2c95dcd6d19c54ceb2fe854799af4ea4)] Update code to editio 2018 (Bruno Tavares) +- [[`310dd8a5d7`](https://github.com/datrs/random-access-disk/commit/310dd8a5d79e2edcfbded8cb48a17c5949c6b276)] Bump random-access-storage to 3.0.0 (Bruno Tavares) +- [[`95c3dad271`](https://github.com/datrs/random-access-disk/commit/95c3dad2715ade75c18337bb72f109573c9c08e3)] updated to use u64 (substack) +- [[`1d884a4432`](https://github.com/datrs/random-access-disk/commit/1d884a443232528c2a0a9e03901cb12eca137ac1)] sync_all implementation (substack) +- [[`bd9d0f6a86`](https://github.com/datrs/random-access-disk/commit/bd9d0f6a869d9f8225ae8582a5bfe5db6ca52578)] Update mkdirp requirement from 0.1.0 to 1.0.0 (dependabot-preview[bot]) +- [[`f9b34735e7`](https://github.com/datrs/random-access-disk/commit/f9b34735e79020ff2f39bef510026f5cf8bf02b3)] Update quickcheck requirement from 0.7.2 to 0.8.0 (dependabot[bot]) +- [[`4785a3dfa5`](https://github.com/datrs/random-access-disk/commit/4785a3dfa5aed164df833eafaeef4edda0dfd2c4)] Update changelog (Yoshua Wuyts) + +### Stats +```diff + CHANGELOG.md | 16 ++++++- + Cargo.toml | 25 ++++----- + fuzz/Cargo.toml | 1 +- + fuzz/fuzz_targets/fuzz_target_1.rs | 6 +-- + src/lib.rs | 109 ++++++++++++++++++++++++-------------- + tests/model.rs | 34 ++++-------- + tests/regression.rs | 5 +-- + tests/test.rs | 82 +++++++++++++++++++++++++++-- + 8 files changed, 194 insertions(+), 84 deletions(-) +``` + + +## 2018-12-20, Version 0.8.0 +### Commits +- [[`c7cdc2d39a`](https://github.com/datrs/random-access-disk/commit/c7cdc2d39a7d92103f7125c28d2451ecf6272578)] (cargo-release) version 0.8.0 (Yoshua Wuyts) +- [[`65bffdf0b8`](https://github.com/datrs/random-access-disk/commit/65bffdf0b8ef6d7b37a89b9ef498fb62a24a2e25)] len() and is_empty() implementation (#21) (James Halliday) +- [[`e6733d9273`](https://github.com/datrs/random-access-disk/commit/e6733d92734e42881ca5f90228eef96883b005a7)] Update changelog (Yoshua Wuyts) + +### Stats +```diff + CHANGELOG.md | 22 ++++++++++++++++++++++ + Cargo.toml | 4 ++-- + src/lib.rs | 8 ++++++++ + tests/test.rs | 38 ++++++++++++++++++++++++++++++++++++++ + 4 files changed, 70 insertions(+), 2 deletions(-) +``` + + +## 2018-11-21, Version 0.7.0 +### Commits +- [[`9059d4f552`](https://github.com/datrs/random-access-disk/commit/9059d4f5524f16f52badff98a92e4b7db308a2d0)] (cargo-release) version 0.7.0 (Yoshua Wuyts) +- [[`791e3fd8ee`](https://github.com/datrs/random-access-disk/commit/791e3fd8ee1fd7af387119e734fd498074fc8c33)] update travis (Yoshua Wuyts) +- [[`4e33df9813`](https://github.com/datrs/random-access-disk/commit/4e33df981357474f1e986e3fef63f5b4397efad0)] truncate implementation with tests (#18) (James Halliday) +- [[`4098c2d35d`](https://github.com/datrs/random-access-disk/commit/4098c2d35dd570d635a890656925ae898e8e9e05)] Update rand requirement from 0.5.5 to 0.6.0 (#17) (dependabot[bot]) +- [[`9083d3cfb0`](https://github.com/datrs/random-access-disk/commit/9083d3cfb08069541a146f7e12e6af06c97354c0)] Update quickcheck requirement from 0.6.2 to 0.7.1 (#15) (dependabot[bot]) +- [[`928fe1afaf`](https://github.com/datrs/random-access-disk/commit/928fe1afaf95453a00bb7754bb7ff91e08fe5689)] Run clippy on travis (#14) (Szabolcs Berecz) +- [[`07fa83dd28`](https://github.com/datrs/random-access-disk/commit/07fa83dd2882d0b6868378e7a9599572693e035e)] update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 23 ++++++++++--------- + CHANGELOG.md | 21 ++++++++++++++++++- + Cargo.toml | 11 ++++----- + src/lib.rs | 10 +++++++- + tests/model.rs | 2 ++- + tests/test.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 6 files changed, 121 insertions(+), 16 deletions(-) +``` + + +## 2018-08-30, Version 0.6.0 +### Commits +- [[`1070eb3166`](https://github.com/datrs/random-access-disk/commits/1070eb31665c3578842997557af292a9e702a033)] (cargo-release) version 0.6.0 (Yoshua Wuyts) +- [[`fb9ee81c81`](https://github.com/datrs/random-access-disk/commits/fb9ee81c81043619ecf6ea3a5d670373248cd677)] Random access always open (#13) (Szabolcs Berecz) +- [[`0a18b10972`](https://github.com/datrs/random-access-disk/commits/0a18b109722c73f7385f77fe7fb7c2d118f7bcae)] replace tempdir crate (deprecated) with tempfile crate, using tempfile::Builder to create a tempdir (#12) (Jacob Burden) +- [[`254d3ccf77`](https://github.com/datrs/random-access-disk/commits/254d3ccf7789e615a46815c0e43f0892aab96eff)] update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 1 +- + CHANGELOG.md | 26 ++++++++++++++++++++++++- + Cargo.toml | 6 ++--- + benches/sync.rs | 29 +++++++++++++++++++-------- + src/lib.rs | 59 +++++++++++++++++++++++++----------------------------- + tests/model.rs | 10 +++++---- + tests/regression.rs | 16 ++++++++++----- + tests/test.rs | 35 +++++++++++++++++++++----------- + 8 files changed, 120 insertions(+), 62 deletions(-) +``` + + +## 2018-08-23, Version 0.5.0 +### Commits +- [[`647536ba06`](https://github.com/datrs/random-access-disk/commits/647536ba06ab55f810c7981e60d68481ec55044c)] (cargo-release) version 0.5.0 (Yoshua Wuyts) +- [[`556d70f09a`](https://github.com/datrs/random-access-disk/commits/556d70f09a0b23cf15107442f9cefec7669ad463)] upgrade random-access-storage (#9) +- [[`61af2acc13`](https://github.com/datrs/random-access-disk/commits/61af2acc135456d39eb05b92e1ad3a20e790e53c)] Fix typo in crates.io link (#10) + (tomasol) +- [[`64f674e8e9`](https://github.com/datrs/random-access-disk/commits/64f674e8e9b7377b209775e5bf31238f6be213cb)] Rename Sync -> RandomAccessDisk in README.md (#11) + (tomasol) +- [[`1860e0ce4d`](https://github.com/datrs/random-access-disk/commits/1860e0ce4d8b0de8fce189beaaad549d79b3d40f)] rm unused src/syc file (Yoshua Wuyts) +- [[`e5089b73ff`](https://github.com/datrs/random-access-disk/commits/e5089b73ffc2a75210fa2c2fab52ee0050486ec6)] fix rustfmt in travis.yml (Yoshua Wuyts) +- [[`7a4448f454`](https://github.com/datrs/random-access-disk/commits/7a4448f454bcc57f158d6c360a5d82727a6a74e9)] remove &* calls (Yoshua Wuyts) +- [[`522cd4219e`](https://github.com/datrs/random-access-disk/commits/522cd4219e8bfd37cb3403f1100d6024f5367f2b)] (cargo-release) start next development iteration 0.4.1-alpha.0 (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 2 +- + Cargo.toml | 4 +- + README.md | 4 +- + src/lib.rs | 26 +++++++++----- + src/sync.rs | 105 +---------------------------------------------------------- + tests/model.rs | 5 +-- + tests/test.rs | 5 +--- + 7 files changed, 26 insertions(+), 125 deletions(-) +``` + + diff --git a/vendor/random-access-disk/Cargo.toml b/vendor/random-access-disk/Cargo.toml new file mode 100644 index 00000000..f00f7099 --- /dev/null +++ b/vendor/random-access-disk/Cargo.toml @@ -0,0 +1,98 @@ +# 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 = "random-access-disk" +version = "3.0.0" +authors = [ + "Yoshua Wuyts ", + "Timo Tiuraniemi ", +] +description = "Continuously read and write to disk, using random offsets and lengths" +documentation = "https://docs.rs/random-access-disk" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/datrs/random-access-disk" + +[[bench]] +name = "sync" +harness = false + +[dependencies.async-std] +version = "1.12.0" +optional = true + +[dependencies.async-trait] +version = "0.1" + +[dependencies.libc] +version = "0.2" +optional = true + +[dependencies.mkdirp] +version = "1.0.0" + +[dependencies.random-access-storage] +version = "5.0.0" + +[dependencies.tokio] +version = "1.27.0" +features = [ + "fs", + "io-util", +] +optional = true + +[dev-dependencies.async-std] +version = "1.12.0" +features = ["attributes"] + +[dev-dependencies.criterion] +version = "0.4" +features = [ + "async_std", + "async_tokio", +] + +[dev-dependencies.proptest] +version = "1.1.0" + +[dev-dependencies.proptest-derive] +version = "0.2.0" + +[dev-dependencies.tempfile] +version = "3.1.0" + +[dev-dependencies.tokio] +version = "1.25.0" +features = [ + "macros", + "rt", + "rt-multi-thread", +] + +[dev-dependencies.tokio-test] +version = "0.4" + +[features] +default = [ + "sparse", + "async-std", +] +sparse = ["libc"] + +[target."cfg(windows)".dependencies.winapi] +version = "0.3.9" +features = [ + "ioapiset", + "winioctl", +] diff --git a/vendor/random-access-disk/LICENSE-APACHE b/vendor/random-access-disk/LICENSE-APACHE new file mode 100644 index 00000000..6ab06963 --- /dev/null +++ b/vendor/random-access-disk/LICENSE-APACHE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018 Yoshua Wuyts + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/random-access-disk/LICENSE-MIT b/vendor/random-access-disk/LICENSE-MIT new file mode 100644 index 00000000..c7509bad --- /dev/null +++ b/vendor/random-access-disk/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Yoshua Wuyts + +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. diff --git a/vendor/random-access-disk/README.md b/vendor/random-access-disk/README.md new file mode 100644 index 00000000..400f0447 --- /dev/null +++ b/vendor/random-access-disk/README.md @@ -0,0 +1,30 @@ +# random-access-disk +[![crates.io version][1]][2] [![build status][3]][4] +[![downloads][5]][6] [![docs.rs docs][7]][8] + +Continuously read and write to disk, using random offsets and lengths, +using abstract interface defined in +[random-access-storage](https://github.com/datrs/random-access-storage). + +Adapted from Javascript +[random-access-file](https://github.com/random-access-storage/random-access-file/). + +- [Documentation][8] +- [Crate][2] + +## Installation +```sh +$ cargo add random-access-disk +``` + +## License +[MIT](./LICENSE-MIT) OR [Apache-2.0](./LICENSE-APACHE) + +[1]: https://img.shields.io/crates/v/random-access-disk.svg?style=flat-square +[2]: https://crates.io/crates/random-access-disk +[3]: https://github.com/datrs/random-access-disk/actions/workflows/ci.yml/badge.svg +[4]: https://github.com/datrs/random-access-disk/actions[ +[5]: https://img.shields.io/crates/d/random-access-disk.svg?style=flat-square +[6]: https://crates.io/crates/random-access-disk +[7]: https://docs.rs/random-access-disk/badge.svg +[8]: https://docs.rs/random-access-disk diff --git a/vendor/random-access-disk/benches/sync.rs b/vendor/random-access-disk/benches/sync.rs new file mode 100644 index 00000000..a99fc281 --- /dev/null +++ b/vendor/random-access-disk/benches/sync.rs @@ -0,0 +1,144 @@ +use std::time::{Duration, Instant}; + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use random_access_disk as rad; +use random_access_storage::RandomAccess; + +#[cfg(feature = "async-std")] +use criterion::async_executor::AsyncStdExecutor; + +fn bench_write_hello_world(c: &mut Criterion) { + #[cfg(feature = "async-std")] + c.bench_function("write hello world", |b| { + b.to_async(AsyncStdExecutor).iter_custom(write_hello_world); + }); + #[cfg(feature = "tokio")] + c.bench_function("write hello world", |b| { + let rt = tokio::runtime::Runtime::new().unwrap(); + b.to_async(&rt).iter_custom(write_hello_world); + }); +} + +#[allow(clippy::unit_arg)] +async fn write_hello_world(iters: u64) -> Duration { + let mut file = create_file("1.db").await; + let start = Instant::now(); + for _ in 0..iters { + black_box( + async { + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + } + .await, + ); + } + start.elapsed() +} + +fn bench_read_hello_world(c: &mut Criterion) { + #[cfg(feature = "async-std")] + c.bench_function("read hello world", |b| { + b.to_async(AsyncStdExecutor).iter_custom(read_hello_world); + }); + #[cfg(feature = "tokio")] + c.bench_function("read hello world", |b| { + let rt = tokio::runtime::Runtime::new().unwrap(); + b.to_async(&rt).iter_custom(read_hello_world); + }); +} + +#[allow(clippy::unit_arg)] +async fn read_hello_world(iters: u64) -> Duration { + let mut file = create_file("2.db").await; + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + let start = Instant::now(); + for _ in 0..iters { + black_box( + async { + let _text = file.read(0, 11).await.unwrap(); + } + .await, + ); + } + start.elapsed() +} + +fn bench_read_write_hello_world(c: &mut Criterion) { + #[cfg(feature = "async-std")] + c.bench_function("read/write hello world", |b| { + b.to_async(AsyncStdExecutor) + .iter_custom(read_write_hello_world); + }); + #[cfg(feature = "tokio")] + c.bench_function("read/write hello world", |b| { + let rt = tokio::runtime::Runtime::new().unwrap(); + b.to_async(&rt).iter_custom(read_write_hello_world); + }); +} + +#[allow(clippy::unit_arg)] +async fn read_write_hello_world(iters: u64) -> Duration { + let mut file = create_file("3.db").await; + let start = Instant::now(); + for _ in 0..iters { + black_box( + async { + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + let _text = file.read(0, 11).await.unwrap(); + } + .await, + ); + } + start.elapsed() +} + +fn bench_write_del_hello_world(c: &mut Criterion) { + #[cfg(feature = "async-std")] + c.bench_function("write/del hello world", |b| { + b.to_async(AsyncStdExecutor) + .iter_custom(write_del_hello_world); + }); + #[cfg(feature = "tokio")] + c.bench_function("write/del hello world", |b| { + let rt = tokio::runtime::Runtime::new().unwrap(); + b.to_async(&rt).iter_custom(write_del_hello_world); + }); +} + +#[allow(clippy::unit_arg)] +async fn write_del_hello_world(iters: u64) -> Duration { + let mut file = create_file("4.db").await; + let start = Instant::now(); + for _ in 0..iters { + black_box( + async { + file.write(0, b"hello world").await.unwrap(); + file.del(0, 5).await.unwrap(); + file.del(5, 6).await.unwrap(); + } + .await, + ); + } + start.elapsed() +} + +async fn create_file(file_name: &str) -> rad::RandomAccessDisk { + let dir = tempfile::Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + rad::RandomAccessDisk::open(dir.path().join(file_name)) + .await + .unwrap() +} + +criterion_group!( + benches, + bench_write_hello_world, + bench_read_hello_world, + bench_read_write_hello_world, + bench_write_del_hello_world, +); +criterion_main!(benches); diff --git a/vendor/random-access-disk/rustfmt.toml b/vendor/random-access-disk/rustfmt.toml new file mode 100644 index 00000000..4c1eefae --- /dev/null +++ b/vendor/random-access-disk/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 80 +tab_spaces = 2 diff --git a/vendor/random-access-disk/src/default.rs b/vendor/random-access-disk/src/default.rs new file mode 100644 index 00000000..c02c6870 --- /dev/null +++ b/vendor/random-access-disk/src/default.rs @@ -0,0 +1,41 @@ +#[cfg(feature = "async-std")] +use async_std::fs; +use random_access_storage::RandomAccessError; +#[cfg(feature = "tokio")] +use tokio::fs; + +/// Get file length and file system block size +pub async fn get_length_and_block_size( + file: &fs::File, +) -> Result<(u64, u64), RandomAccessError> { + let metadata = file.metadata().await?; + Ok((metadata.len(), 0)) +} + +/// Set file to sparse, not applicable +pub async fn set_sparse(_file: &mut fs::File) -> Result<(), RandomAccessError> { + Ok(()) +} + +/// Non-sparse trimming of a file to zeros +pub async fn trim( + file: &mut fs::File, + offset: u64, + length: u64, + _block_size: u64, +) -> Result<(), RandomAccessError> { + #[cfg(feature = "async-std")] + use async_std::io::{ + prelude::{SeekExt, WriteExt}, + SeekFrom, + }; + #[cfg(feature = "tokio")] + use std::io::SeekFrom; + #[cfg(feature = "tokio")] + use tokio::io::{AsyncSeekExt, AsyncWriteExt}; + + let data = vec![0_u8; length as usize]; + file.seek(SeekFrom::Start(offset)).await?; + file.write_all(&data).await?; + Ok(()) +} diff --git a/vendor/random-access-disk/src/lib.rs b/vendor/random-access-disk/src/lib.rs new file mode 100644 index 00000000..7f4e4ccf --- /dev/null +++ b/vendor/random-access-disk/src/lib.rs @@ -0,0 +1,388 @@ +#![forbid(missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![doc(test(attr(deny(warnings))))] + +//! # Continuously read and write to disk, using random offsets and lengths +//! [RandomAccessDisk] is a complete implementation of [random-access-storage](https://docs.rs/random-access-storage) +//! for in-memory storage. +//! +//! See also [random-access-memory](https://docs.rs/random-access-memory) for in-memory storage +//! that can be swapped with this. +//! +//! ## Features +//! +//! ### `sparse` (default) +//! +//! Deleting may create sparse files, on by default. Creation of sparse files is tested on OSX, linux and Windows. +//! +//! **NB**: If this is on, `unsafe` code is used to make direct platform-specific calls! +//! +//! ### `async-std` (default) +//! +//! Use the async-std runtime, on by default. Either this or `tokio` is mandatory. +//! +//! ### `tokio` +//! +//! Use the tokio runtime. Either this or `async_std` is mandatory. +//! +//! ## Examples +//! +//! Reading, writing, deleting and truncating: +//! +//! ``` +//! # #[cfg(feature = "tokio")] +//! # tokio_test::block_on(async { +//! # example().await; +//! # }); +//! # #[cfg(feature = "async-std")] +//! # async_std::task::block_on(async { +//! # example().await; +//! # }); +//! # async fn example() { +//! use random_access_storage::RandomAccess; +//! use random_access_disk::RandomAccessDisk; +//! +//! let path = tempfile::Builder::new().prefix("basic").tempfile().unwrap().into_temp_path(); +//! let mut storage = RandomAccessDisk::open(path.to_path_buf()).await.unwrap(); +//! storage.write(0, b"hello").await.unwrap(); +//! storage.write(5, b" world").await.unwrap(); +//! assert_eq!(storage.read(0, 11).await.unwrap(), b"hello world"); +//! assert_eq!(storage.len().await.unwrap(), 11); +//! storage.del(5, 2).await.unwrap(); +//! assert_eq!(storage.read(5, 2).await.unwrap(), [0, 0]); +//! assert_eq!(storage.len().await.unwrap(), 11); +//! storage.truncate(2).await.unwrap(); +//! assert_eq!(storage.len().await.unwrap(), 2); +//! storage.truncate(5).await.unwrap(); +//! assert_eq!(storage.len().await.unwrap(), 5); +//! assert_eq!(storage.read(0, 5).await.unwrap(), [b'h', b'e', 0, 0, 0]); +//! # } +//! ``` +//! +//! In order to get benefits from the swappable interface, you will +//! in most cases want to use generic functions for storage manipulation: +//! +//! ``` +//! # #[cfg(feature = "tokio")] +//! # tokio_test::block_on(async { +//! # example().await; +//! # }); +//! # #[cfg(feature = "async-std")] +//! # async_std::task::block_on(async { +//! # example().await; +//! # }); +//! # async fn example() { +//! use random_access_storage::RandomAccess; +//! use random_access_disk::RandomAccessDisk; +//! use std::fmt::Debug; +//! +//! let path = tempfile::Builder::new().prefix("swappable").tempfile().unwrap().into_temp_path(); +//! let mut storage = RandomAccessDisk::open(path.to_path_buf()).await.unwrap(); +//! write_hello_world(&mut storage).await; +//! assert_eq!(read_hello_world(&mut storage).await, b"hello world"); +//! +//! /// Write with swappable storage +//! async fn write_hello_world(storage: &mut T) +//! where T: RandomAccess + Debug + Send, +//! { +//! storage.write(0, b"hello").await.unwrap(); +//! storage.write(5, b" world").await.unwrap(); +//! } +//! +//! /// Read with swappable storage +//! async fn read_hello_world(storage: &mut T) -> Vec +//! where T: RandomAccess + Debug + Send, +//! { +//! storage.read(0, 11).await.unwrap() +//! } +//! # } + +#[cfg(not(any(feature = "async-std", feature = "tokio")))] +compile_error!( + "Either feature `random-access-disk/async-std` or `random-access-disk/tokio` must be enabled." +); + +#[cfg(all(feature = "async-std", feature = "tokio"))] +compile_error!("features `random-access-disk/async-std` and `random-access-disk/tokio` are mutually exclusive"); + +#[cfg(feature = "async-std")] +use async_std::{ + fs::{self, OpenOptions}, + io::prelude::{SeekExt, WriteExt}, + io::{ReadExt, SeekFrom}, +}; +use random_access_storage::{RandomAccess, RandomAccessError}; +use std::ops::Drop; +use std::path; + +#[cfg(feature = "tokio")] +use std::io::SeekFrom; +#[cfg(feature = "tokio")] +use tokio::{ + fs::{self, OpenOptions}, + io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}, +}; + +#[cfg(all( + feature = "sparse", + any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "macos", + ) +))] +mod unix; +#[cfg(all( + feature = "sparse", + any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "macos", + ) +))] +use unix::{get_length_and_block_size, set_sparse, trim}; + +#[cfg(all(feature = "sparse", windows))] +mod windows; +#[cfg(all(feature = "sparse", windows))] +use windows::{get_length_and_block_size, set_sparse, trim}; + +#[cfg(not(all( + feature = "sparse", + any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "macos", + windows, + ) +)))] +mod default; + +#[cfg(not(all( + feature = "sparse", + any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "macos", + windows, + ) +)))] +use default::{get_length_and_block_size, set_sparse, trim}; + +/// Main constructor. +#[derive(Debug)] +pub struct RandomAccessDisk { + #[allow(dead_code)] + filename: path::PathBuf, + file: Option, + length: u64, + block_size: u64, + auto_sync: bool, +} + +impl RandomAccessDisk { + /// Create a new (auto-sync) instance to storage at `filename`. + #[allow(clippy::new_ret_no_self)] + pub async fn open( + filename: path::PathBuf, + ) -> Result { + Self::builder(filename).build().await + } + + /// Initialize a builder with storage at `filename`. + pub fn builder(filename: path::PathBuf) -> Builder { + Builder::new(filename) + } +} + +#[async_trait::async_trait] +impl RandomAccess for RandomAccessDisk { + async fn write( + &mut self, + offset: u64, + data: &[u8], + ) -> Result<(), RandomAccessError> { + let file = self.file.as_mut().expect("self.file was None."); + file.seek(SeekFrom::Start(offset)).await?; + file.write_all(data).await?; + if self.auto_sync { + file.sync_all().await?; + } + + // We've changed the length of our file. + let new_len = offset + (data.len() as u64); + if new_len > self.length { + self.length = new_len; + } + + Ok(()) + } + + // NOTE(yw): disabling clippy here because we files on disk might be sparse, + // and sometimes you might want to read a bit of memory to check if it's + // formatted or not. Returning zero'd out memory seems like an OK thing to do. + // We should probably come back to this at a future point, and determine + // whether it's okay to return a fully zero'd out slice. It's a bit weird, + // because we're replacing empty data with actual zeroes - which does not + // reflect the state of the world. + // #[cfg_attr(test, allow(unused_io_amount))] + async fn read( + &mut self, + offset: u64, + length: u64, + ) -> Result, RandomAccessError> { + if offset + length > self.length { + return Err(RandomAccessError::OutOfBounds { + offset, + end: Some(offset + length), + length: self.length, + }); + } + + let file = self.file.as_mut().expect("self.file was None."); + let mut buffer = vec![0; length as usize]; + file.seek(SeekFrom::Start(offset)).await?; + let _bytes_read = file.read(&mut buffer[..]).await?; + Ok(buffer) + } + + async fn del( + &mut self, + offset: u64, + length: u64, + ) -> Result<(), RandomAccessError> { + if offset > self.length { + return Err(RandomAccessError::OutOfBounds { + offset, + end: None, + length: self.length, + }); + }; + + if length == 0 { + // No-op + return Ok(()); + } + + // Delete is truncate if up to the current length or more is deleted + if offset + length >= self.length { + return self.truncate(offset).await; + } + + let file = self.file.as_mut().expect("self.file was None."); + trim(file, offset, length, self.block_size).await?; + if self.auto_sync { + file.sync_all().await?; + } + Ok(()) + } + + async fn truncate(&mut self, length: u64) -> Result<(), RandomAccessError> { + let file = self.file.as_ref().expect("self.file was None."); + self.length = length; + file.set_len(self.length).await?; + if self.auto_sync { + file.sync_all().await?; + } + Ok(()) + } + + async fn len(&mut self) -> Result { + Ok(self.length) + } + + async fn is_empty(&mut self) -> Result { + Ok(self.length == 0) + } + + async fn sync_all(&mut self) -> Result<(), RandomAccessError> { + if !self.auto_sync { + let file = self.file.as_ref().expect("self.file was None."); + file.sync_all().await?; + } + Ok(()) + } +} + +impl Drop for RandomAccessDisk { + fn drop(&mut self) { + // We need to flush the file on drop. Unfortunately, that is not possible to do in a + // non-blocking fashion, but our only other option here is losing data remaining in the + // write cache. Good task schedulers should be resilient to occasional blocking hiccups in + // file destructors so we don't expect this to be a common problem in practice. + // (from async_std::fs::File::drop) + #[cfg(feature = "async-std")] + if let Some(file) = &self.file { + let _ = async_std::task::block_on(file.sync_all()); + } + // For tokio, the below errors with: + // + // "Cannot start a runtime from within a runtime. This happens because a function (like + // `block_on`) attempted to block the current thread while the thread is being used to + // drive asynchronous tasks." + // + // There doesn't seem to be an equivalent block_on version for tokio that actually works + // in a sync drop(), so for tokio, we'll need to wait for a real AsyncDrop to arrive. + // + // #[cfg(feature = "tokio")] + // if let Some(file) = &self.file { + // tokio::runtime::Handle::current() + // .block_on(file.sync_all()) + // .expect("Could not sync file changes on drop."); + // } + } +} + +/// Builder for [RandomAccessDisk] +pub struct Builder { + filename: path::PathBuf, + auto_sync: bool, +} + +impl Builder { + /// Create new builder at `path` (with auto-sync true by default). + pub fn new(filename: path::PathBuf) -> Self { + Self { + filename, + auto_sync: true, + } + } + + /// Set auto-sync + // NB: Because of no AsyncDrop, tokio can not ensure that changes are synced when dropped, + // see impl Drop above. + #[cfg(feature = "async-std")] + pub fn auto_sync(mut self, auto_sync: bool) -> Self { + self.auto_sync = auto_sync; + self + } + + /// Build a [RandomAccessDisk] instance + pub async fn build(self) -> Result { + if let Some(dirname) = self.filename.parent() { + mkdirp::mkdirp(dirname)?; + } + let mut file = OpenOptions::new() + .create(true) + .read(true) + .write(true) + .open(&self.filename) + .await?; + file.sync_all().await?; + + set_sparse(&mut file).await?; + + let (length, block_size) = get_length_and_block_size(&file).await?; + Ok(RandomAccessDisk { + filename: self.filename, + file: Some(file), + length, + auto_sync: self.auto_sync, + block_size, + }) + } +} diff --git a/vendor/random-access-disk/src/unix.rs b/vendor/random-access-disk/src/unix.rs new file mode 100644 index 00000000..7fe2f1c1 --- /dev/null +++ b/vendor/random-access-disk/src/unix.rs @@ -0,0 +1,190 @@ +#[cfg(feature = "async-std")] +use async_std::fs; +use random_access_storage::RandomAccessError; +#[cfg(feature = "tokio")] +use tokio::fs; + +/// Get unix file length and file system block size +pub async fn get_length_and_block_size( + file: &fs::File, +) -> Result<(u64, u64), RandomAccessError> { + use std::os::unix::fs::MetadataExt; + let meta = file.metadata().await?; + let block_size = meta.blksize(); + Ok((meta.len(), block_size)) +} + +/// Set file to sparse, not applicable in unix +pub async fn set_sparse(_file: &mut fs::File) -> Result<(), RandomAccessError> { + Ok(()) +} + +/// Linux-specific trimming to sparse files +#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] +pub async fn trim( + file: &mut fs::File, + offset: u64, + length: u64, + _block_size: u64, +) -> Result<(), RandomAccessError> { + use libc::{fallocate, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE}; + use std::os::unix::io::AsRawFd; + + let fd = file.as_raw_fd(); + unsafe { + let ret = fallocate( + fd, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + offset as libc::off_t, + length as libc::off_t, + ); + + if ret < 0 { + return Err(RandomAccessError::IO { + context: Some("Failed to punch hole to file on linux".to_string()), + return_code: Some(ret), + source: std::io::Error::last_os_error(), + }); + } + } + + Ok(()) +} + +/// OSX-specific trimming of a file to a sparse file +#[cfg(target_os = "macos")] +pub async fn trim( + file: &mut fs::File, + offset: u64, + length: u64, + block_size: u64, +) -> Result<(), RandomAccessError> { + #[cfg(feature = "async-std")] + use async_std::io::{ + prelude::{SeekExt, WriteExt}, + SeekFrom, + }; + #[cfg(feature = "tokio")] + use std::io::SeekFrom; + #[cfg(feature = "tokio")] + use tokio::io::{AsyncSeekExt, AsyncWriteExt}; + + if length == 0 { + return Ok(()); + } + + // Find distance to next block + let next_block_distance: u64 = if offset % block_size == 0 { + 0 + } else { + block_size - offset % block_size + }; + + // Find offset to from end to the last block + let end = offset + length; + let last_block_offset = end - (end % block_size); + + // Find out how much initially be zeroed + let initial_zero_length = if offset + next_block_distance >= last_block_offset + { + // This is the simple case of nothing to hole punch + length + } else { + next_block_distance + }; + + if initial_zero_length > 0 { + // Needs zeroing + let data = vec![0_u8; initial_zero_length as usize]; + file.seek(SeekFrom::Start(offset)).await?; + file.write_all(&data).await?; + if initial_zero_length == length { + // This was the simple case of zeroing without hole punching + return Ok(()); + } + } + + // Now see if there are blocks in the middle that can be punched + // into holes + let punch_hole_offset = offset + next_block_distance; + + if punch_hole_offset < last_block_offset { + // There is a t least one block that can be punched + punch_hole( + file, + punch_hole_offset, + last_block_offset - punch_hole_offset, + )?; + } + + if last_block_offset < end { + // Needs zeroing of the last block + let data = vec![0_u8; (end - last_block_offset) as usize]; + file.seek(SeekFrom::Start(last_block_offset)).await?; + file.write_all(&data).await?; + } + + Ok(()) +} + +/// OSX-specific punching of a hole to a file. Works only with offset and length +/// that matches file system block boundaries. +#[cfg(target_os = "macos")] +fn punch_hole( + file: &fs::File, + offset: u64, + length: u64, +) -> Result<(), RandomAccessError> { + // fcntl.h has this, which is not yet covered by libc: + // + // #define F_PUNCHHOLE 99 /* Deallocate a range of the file */ + // + // /* fpunchhole_t used by F_PUNCHHOLE */ + // typedef struct fpunchhole { + // unsigned int fp_flags; /* unused */ + // unsigned int reserved; /* (to maintain 8-byte alignment) */ + // off_t fp_offset; /* IN: start of the region */ + // off_t fp_length; /* IN: size of the region */ + // } fpunchhole_t; + // + // F_PUNCHHOLE Deallocate a region and replace it with a hole. + // Subsequent reads of the affected region will return bytes of + // zeros that are usually not backed by physical blocks. This will + // not change the actual file size. Holes must be aligned to file + // system block boundaries. This will fail on file systems that do + // not support this interface. + + use libc::c_int; + use std::os::unix::io::AsRawFd; + + let fd = file.as_raw_fd(); + + #[repr(C)] + struct fpunchhole_t { + fp_flags: c_int, /* unused */ + reserved: c_int, /* (to maintain 8-byte alignment) */ + fp_offset: u64, /* IN: start of the region */ + fp_length: u64, /* IN: size of the region */ + } + const F_PUNCHHOLE: c_int = 99; + + let hole = fpunchhole_t { + fp_flags: 0, + reserved: 0, + fp_offset: offset, + fp_length: length, + }; + + unsafe { + let ret = libc::fcntl(fd, F_PUNCHHOLE, &hole); + if ret < 0 { + return Err(RandomAccessError::IO { + context: Some("Failed to punch hole to file on macos".to_string()), + return_code: Some(ret), + source: std::io::Error::last_os_error(), + }); + } + } + + Ok(()) +} diff --git a/vendor/random-access-disk/src/windows.rs b/vendor/random-access-disk/src/windows.rs new file mode 100644 index 00000000..abae3012 --- /dev/null +++ b/vendor/random-access-disk/src/windows.rs @@ -0,0 +1,94 @@ +use random_access_storage::RandomAccessError; +use std::os::windows::prelude::{AsRawHandle, RawHandle}; + +use winapi::shared::minwindef::{DWORD, LPVOID}; +use winapi::um::ioapiset::DeviceIoControl; +use winapi::um::winioctl::FSCTL_SET_SPARSE; +use winapi::um::winioctl::FSCTL_SET_ZERO_DATA; + +#[cfg(feature = "async-std")] +use async_std::fs; +#[cfg(feature = "tokio")] +use tokio::fs; + +pub async fn get_length_and_block_size( + file: &fs::File, +) -> Result<(u64, u64), RandomAccessError> { + let meta = file.metadata().await?; + Ok((meta.len(), 0)) +} + +/// Set file to sparse +pub async fn set_sparse(file: &mut fs::File) -> Result<(), RandomAccessError> { + unsafe { + device_io_control( + file.as_raw_handle(), + FSCTL_SET_SPARSE, + &None::>, + std::ptr::null_mut() as *mut (), + 0, + )?; + }; + + Ok(()) +} + +/// Windows-specific trimming of a file to a sparse file +pub async fn trim( + file: &fs::File, + offset: u64, + length: u64, + _block_size: u64, +) -> Result<(), RandomAccessError> { + unsafe { + device_io_control( + file.as_raw_handle(), + FSCTL_SET_ZERO_DATA, + &FileZeroDataInformation { + offset, + beyond_final_zero: offset + length, + }, + std::ptr::null_mut() as *mut (), + 0, + )?; + }; + Ok(()) +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct FileZeroDataInformation { + offset: u64, + beyond_final_zero: u64, +} + +unsafe fn device_io_control( + handle: RawHandle, + control_code: DWORD, + query: &Q, + result: *mut R, + capacity: usize, +) -> Result { + let mut returned_bytes: DWORD = 0; + + let ret = DeviceIoControl( + handle as _, + control_code, + query as *const _ as LPVOID, + std::mem::size_of::() as DWORD, + result as LPVOID, + capacity as DWORD, + &mut returned_bytes, + std::ptr::null_mut(), + ); + + if ret == 0 { + return Err(RandomAccessError::IO { + context: Some("DeviceIoControl failed on windows".to_string()), + return_code: Some(ret), + source: std::io::Error::last_os_error(), + }); + } + + Ok(returned_bytes as usize) +} diff --git a/vendor/random-access-disk/tests/model.rs b/vendor/random-access-disk/tests/model.rs new file mode 100644 index 00000000..c28a7d7e --- /dev/null +++ b/vendor/random-access-disk/tests/model.rs @@ -0,0 +1,122 @@ +use self::Op::*; +use proptest::prelude::*; +use proptest::test_runner::FileFailurePersistence; +use proptest_derive::Arbitrary; +use random_access_disk::RandomAccessDisk; +use random_access_storage::RandomAccess; +use tempfile::Builder; + +const MAX_FILE_SIZE: u64 = 50000; + +#[derive(Clone, Debug, Arbitrary)] +enum Op { + Read { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(strategy(offset_length_strategy))] + length: u64, + }, + Write { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(regex(data_regex))] + data: Vec, + }, + Delete { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(strategy(offset_length_strategy))] + length: u64, + }, +} + +fn offset_length_strategy() -> impl Strategy { + 0..MAX_FILE_SIZE +} + +fn data_regex() -> &'static str { + // Write 0..5000 byte chunks of ASCII characters as dummy data + "([ -~]{1,1}\n){0,5000}" +} + +proptest! { + #![proptest_config(ProptestConfig { + failure_persistence: Some(Box::new(FileFailurePersistence::WithSource("regressions"))), + ..Default::default() + })] + + #[test] + #[cfg(feature = "async-std")] + fn implementation_matches_model(ops: Vec) { + assert!(async_std::task::block_on(async { + assert_implementation_matches_model(ops).await + })); + } + + #[test] + #[cfg(feature = "tokio")] + fn implementation_matches_model(ops: Vec) { + let rt = tokio::runtime::Runtime::new().unwrap(); + assert!(rt.block_on(async { + assert_implementation_matches_model(ops).await + })); + } +} + +async fn assert_implementation_matches_model(ops: Vec) -> bool { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + + let mut implementation = RandomAccessDisk::open(dir.path().join("1.db")) + .await + .unwrap(); + let mut model = vec![]; + + for op in ops { + match op { + Read { offset, length } => { + let end = offset + length; + if model.len() as u64 >= end { + assert_eq!( + implementation + .read(offset, length) + .await + .expect("Reads should be successful."), + &model[offset as usize..end as usize] + ); + } else { + assert!(implementation.read(offset, length).await.is_err()); + } + } + Write { offset, ref data } => { + let end = offset + (data.len() as u64); + if (model.len() as u64) < end { + model.resize(end as usize, 0); + } + implementation + .write(offset, data) + .await + .expect("Writes should be successful."); + model[offset as usize..end as usize].copy_from_slice(data); + } + Delete { offset, length } => { + if model.len() >= offset as usize { + implementation + .del(offset, length) + .await + .expect("Deletes should be successful."); + if offset + length < model.len() as u64 { + model[offset as usize..(offset + length) as usize].fill(0); + } else { + model.resize(offset as usize, 0); + }; + } else { + assert!(implementation.del(offset, length).await.is_err()); + } + } + } + } + true +} diff --git a/vendor/random-access-disk/tests/regression.rs b/vendor/random-access-disk/tests/regression.rs new file mode 100644 index 00000000..4b69d9a4 --- /dev/null +++ b/vendor/random-access-disk/tests/regression.rs @@ -0,0 +1,37 @@ +use random_access_disk as rad; +use random_access_storage::RandomAccess; +use std::env; +use tempfile::Builder; + +#[cfg(feature = "async-std")] +use async_std::test as async_test; +#[cfg(feature = "tokio")] +use tokio::test as async_test; + +#[async_test] +// postmortem: read_exact wasn't behaving like we hoped, so we had to switch +// back to `.read()` and disable clippy for that rule specifically. +async fn regress_1() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = + rad::RandomAccessDisk::open(dir.path().join("regression-1.db")) + .await + .unwrap(); + file.write(27, b"").await.unwrap(); + file.read(13, 5).await.unwrap(); +} + +#[async_test] +// postmortem: accessing the same file twice would fail, so we had to switch to +// from `.create_new()` to `.create()`. +// +// NOTE: test needs to be run twice in a row to trigger regression. I'm sorry. +async fn regress_2() { + let mut dir = env::temp_dir(); + dir.push("regression-2.db"); + let mut file = rad::RandomAccessDisk::open(dir).await.unwrap(); + file.write(27, b"").await.unwrap(); +} diff --git a/vendor/random-access-disk/tests/test.rs b/vendor/random-access-disk/tests/test.rs new file mode 100644 index 00000000..a0e67f49 --- /dev/null +++ b/vendor/random-access-disk/tests/test.rs @@ -0,0 +1,373 @@ +use random_access_disk as rad; +use random_access_storage::RandomAccess; +use std::io::Read; +use tempfile::Builder; + +#[cfg(feature = "async-std")] +use async_std::test as async_test; +#[cfg(feature = "tokio")] +use tokio::test as async_test; + +#[async_test] +async fn can_call_new() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let _file = rad::RandomAccessDisk::open(dir.path().join("1.db")) + .await + .unwrap(); +} + +#[async_test] +async fn can_open_buffer() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("2.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); +} + +#[async_test] +async fn can_write() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("3.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); +} + +#[async_test] +async fn can_read() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("4.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello world"); +} + +#[async_test] +async fn can_truncate_lt() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("5.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(7).await.unwrap(); + let text = file.read(0, 7).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello w"); + if file.read(0, 8).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("5.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello w"); +} + +#[async_test] +async fn can_truncate_gt() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("6.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(15).await.unwrap(); + let text = file.read(0, 15).await.unwrap(); + assert_eq!( + String::from_utf8(text.to_vec()).unwrap(), + "hello world\0\0\0\0" + ); + if file.read(0, 16).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("6.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello world\0\0\0\0"); +} + +#[async_test] +async fn can_truncate_eq() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("7.db")) + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(11).await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello world"); + if file.read(0, 12).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("7.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello world"); +} + +#[async_test] +async fn can_len() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("8.db")) + .await + .unwrap(); + assert_eq!(file.len().await.unwrap(), 0); + file.write(0, b"hello").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 5); + file.write(5, b" world").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 11); + file.truncate(15).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 15); + file.truncate(8).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 8); +} + +#[async_test] +async fn can_is_empty() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::open(dir.path().join("9.db")) + .await + .unwrap(); + assert!(file.is_empty().await.unwrap()); + file.write(0, b"hello").await.unwrap(); + assert!(!file.is_empty().await.unwrap()); + file.truncate(0).await.unwrap(); + assert!(file.is_empty().await.unwrap()); + file.truncate(1).await.unwrap(); + assert!(!file.is_empty().await.unwrap()); + file.truncate(0).await.unwrap(); + assert!(file.is_empty().await.unwrap()); + file.write(0, b"what").await.unwrap(); + assert!(!file.is_empty().await.unwrap()); +} + +#[async_test] +#[cfg(feature = "async-std")] +async fn explicit_no_auto_sync() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("10.db")) + .auto_sync(false) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(11).await.unwrap(); + file.sync_all().await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello world"); + if file.read(0, 12).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("10.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello world"); +} + +#[async_test] +async fn auto_sync() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("11.db")) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(11).await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello world"); + if file.read(0, 12).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("11.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello world"); +} + +#[async_test] +async fn auto_sync_with_sync_call() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("12.db")) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.truncate(11).await.unwrap(); + file.sync_all().await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello world"); + if file.read(0, 12).await.is_ok() { + panic!("file is too big. read past the end should have failed"); + }; + let mut c_file = std::fs::File::open(dir.path().join("12.db")).unwrap(); + let mut c_contents = String::new(); + c_file.read_to_string(&mut c_contents).unwrap(); + assert_eq!(c_contents, "hello world"); +} + +#[async_test] +async fn can_del_short() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("13.db")) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.write(11, b" people").await.unwrap(); + file.del(5, 6).await.unwrap(); + let hello = file.read(0, 5).await.unwrap(); + assert_eq!(String::from_utf8(hello.to_vec()).unwrap(), "hello"); + let zeros = file.read(5, 6).await.unwrap(); + assert_eq!(zeros, vec![0; 6]); + let people = file.read(12, 6).await.unwrap(); + assert_eq!(String::from_utf8(people.to_vec()).unwrap(), "people"); +} + +#[async_test] +async fn can_del_long_middle() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("14.db")) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + const MULTI_BLOCK_LEN: usize = 4096 * 3; + let multi_block = &[0x61_u8; MULTI_BLOCK_LEN]; + file.write(5, multi_block).await.unwrap(); + file + .write((MULTI_BLOCK_LEN + 5) as u64, b"to all the ") + .await + .unwrap(); + file + .write((MULTI_BLOCK_LEN + 16) as u64, b"people") + .await + .unwrap(); + file.del(5, MULTI_BLOCK_LEN as u64).await.unwrap(); + let hello = file.read(0, 5).await.unwrap(); + assert_eq!(String::from_utf8(hello.to_vec()).unwrap(), "hello"); + let zeros = file.read(5, 10).await.unwrap(); + assert_eq!(zeros, vec![0; 10]); + let zeros = file.read(MULTI_BLOCK_LEN as u64, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + let zeros = file.read((MULTI_BLOCK_LEN / 2) as u64, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + let to_all_the_people = + file.read((MULTI_BLOCK_LEN + 5) as u64, 17).await.unwrap(); + assert_eq!( + String::from_utf8(to_all_the_people.to_vec()).unwrap(), + "to all the people" + ); + file.del((MULTI_BLOCK_LEN + 7) as u64, 4).await.unwrap(); + let zeros = file.read((MULTI_BLOCK_LEN + 7) as u64, 4).await.unwrap(); + assert_eq!(zeros, vec![0; 4]); + let to = file.read((MULTI_BLOCK_LEN + 5) as u64, 2).await.unwrap(); + assert_eq!(String::from_utf8(to.to_vec()).unwrap(), "to"); +} + +#[async_test] +async fn can_del_long_exact_block() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("15.db")) + .build() + .await + .unwrap(); + const BLOCK_LEN: usize = 4096; + let block = &[0x61_u8; BLOCK_LEN + 1]; + file.write(0, block).await.unwrap(); + file.del(0, BLOCK_LEN as u64).await.unwrap(); + let zeros = file.read(0, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + let zeros = file.read(BLOCK_LEN as u64 - 5, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + file.del(0, (BLOCK_LEN + 1) as u64).await.unwrap(); + assert_eq!(0, file.len().await.unwrap()); +} + +#[async_test] +async fn can_del_long_more_than_block() { + let dir = Builder::new() + .prefix("random-access-disk") + .tempdir() + .unwrap(); + let mut file = rad::RandomAccessDisk::builder(dir.path().join("16.db")) + .build() + .await + .unwrap(); + file.write(0, b"hello").await.unwrap(); + const MORE_THAN_BLOCK_LEN: usize = 4096 + 1000; + let more_than_block = &[0x61_u8; MORE_THAN_BLOCK_LEN + 1]; + file.write(5, more_than_block).await.unwrap(); + file.del(5, MORE_THAN_BLOCK_LEN as u64).await.unwrap(); + let zeros = file.read(5, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + let zeros = file.read(MORE_THAN_BLOCK_LEN as u64, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + + const EXACT_TO_THIRD_BLOCK_LEN: usize = 4096 * 2 - 5; + let exact_to_third_block = &[0x61_u8; EXACT_TO_THIRD_BLOCK_LEN + 1]; + file.write(5, exact_to_third_block).await.unwrap(); + file.del(5, EXACT_TO_THIRD_BLOCK_LEN as u64).await.unwrap(); + let zeros = file.read(5, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + let zeros = file.read(EXACT_TO_THIRD_BLOCK_LEN as u64, 5).await.unwrap(); + assert_eq!(zeros, vec![0; 5]); + file + .del(5, (EXACT_TO_THIRD_BLOCK_LEN * 2) as u64) + .await + .unwrap(); + assert_eq!(5, file.len().await.unwrap()); +} diff --git a/vendor/random-access-memory/.cargo-checksum.json b/vendor/random-access-memory/.cargo-checksum.json new file mode 100644 index 00000000..e11c8793 --- /dev/null +++ b/vendor/random-access-memory/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CERTIFICATE":"53a0a460f8eccb279580aa16013c5f98936eba73554d267632f5ea83d8e890b1","CHANGELOG.md":"4977696a6ed0698e62a742c53eb4349f942a2ab1c52476bdb0a04a4cf148863b","Cargo.toml":"102f0e0f5749cb3aca688d9cd33bb3f6fe1eaf6176ab83ea64d4ab45ca3ef178","LICENSE-APACHE":"40b135370517318ee023f4553b49453ab716f4277ccc7801beb3a44ec481c9fb","LICENSE-MIT":"a06326997c80661a79a99f66af7417f3420640323952c92afae69d5a4b7537ee","README.md":"b35809a9ea888e94794dc4039c085eb3dc75e112b70b777dd6edff19a9aee0e0","benches/sync.rs":"e7c425c83208c41c269860bd96ebbaf0b948e8b1ab2a3f0760836673cff7ad16","rustfmt.toml":"bd5701c9a978dcf1d7663447ca8aca21019a06cfe21f67863f459f80b8136f1a","src/lib.rs":"ccabeaa0b425616808dc9c7e0953d8857270fd507c1f087e1230279a10f49ae7","tests/model.rs":"0facbcaaf8af5b69f5c991a05a0bd00e4a458033024b51961398d3a6cbe5fafc","tests/regression.rs":"2fe387a674e2ea0ff487a6941bc9101dc6a673412b342a3a31e618584fbd0789","tests/test.rs":"37927f73eb80b0d6243accd155504c453a83a0d80c81242e19f67a7da58f045c"},"package":"f7231c6b2119fc18cc880baac5041f60d4081fd9ef2eab179caf52a6eb1ac441"} \ No newline at end of file diff --git a/vendor/random-access-memory/CERTIFICATE b/vendor/random-access-memory/CERTIFICATE new file mode 100644 index 00000000..8201f992 --- /dev/null +++ b/vendor/random-access-memory/CERTIFICATE @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/random-access-memory/CHANGELOG.md b/vendor/random-access-memory/CHANGELOG.md new file mode 100644 index 00000000..620924ec --- /dev/null +++ b/vendor/random-access-memory/CHANGELOG.md @@ -0,0 +1,98 @@ +## 2020-03-03, Version 2.0.0 +### Commits +- [[`cab67711c4`](https://github.com/datrs/random-access-memory/commit/cab67711c42f6229fcf01fac0bfae0b5d0a3fe86)] (cargo-release) version 2.0.0 (Bruno Tavares) +- [[`fc07e9cfef`](https://github.com/datrs/random-access-memory/commit/fc07e9cfefdc808f950fada80df7bfe697eaad6d)] Implement async API for random-access-storage (#26) (Bruno Tavares) +- [[`c10203a920`](https://github.com/datrs/random-access-memory/commit/c10203a9206c6e5f93f31b34998096fa1828d947)] Update changelog (Bruno Tavares) + +### Stats +```diff + CHANGELOG.md | 13 +++++++++++++ + Cargo.toml | 7 +++++-- + README.md | 8 ++++---- + benches/sync.rs | 39 +++++++++++++++++++++++---------------- + src/lib.rs | 28 ++++++++++++++++++---------- + tests/model.rs | 52 +++++++++++++++++++++++++++------------------------- + tests/regression.rs | 36 ++++++++++++++++++------------------ + tests/test.rs | 52 ++++++++++++++++++++++++++-------------------------- + 8 files changed, 134 insertions(+), 101 deletions(-) +``` + + +## 2020-03-03, Version 1.2.0 +### Commits +- [[`d9fbf73cf1`](https://github.com/datrs/random-access-memory/commit/d9fbf73cf182e6f02e5adc4c016afe38e8650a88)] (cargo-release) version 1.2.0 (Bruno Tavares) +- [[`0b845fbcc7`](https://github.com/datrs/random-access-memory/commit/0b845fbcc747093d8c9eae972e92c8d4a692a208)] Move from failure to use stderr (#25) (Bruno Tavares) + +### Stats +```diff + Cargo.toml | 4 ++-- + src/lib.rs | 24 +++++++++++++----------- + 2 files changed, 15 insertions(+), 13 deletions(-) +``` + + +## 2019-04-24, Version 1.0.0 +### Commits +- [[`a7ff8ea564`](https://github.com/datrs/random-access-memory/commit/a7ff8ea564f11673b3e39d605befe9b25fc58574)] (cargo-release) version 1.0.0 (Yoshua Wuyts) +- [[`76c0ebfe1b`](https://github.com/datrs/random-access-memory/commit/76c0ebfe1ba046871430f03fe5876a4e27554fb6)] Update random-access-storage to 2.0.0 (#12) (Jack Jennings) +- [[`defaf55071`](https://github.com/datrs/random-access-memory/commit/defaf55071de68206eada89a74616d26603e2faa)] Update quickcheck requirement from 0.7.1 to 0.8.1 (dependabot[bot]) +- [[`42023a8700`](https://github.com/datrs/random-access-memory/commit/42023a870050fdbc196c6f7d2ffd3e7c36797fac)] Update rand requirement from 0.5.5 to 0.6.0 (dependabot[bot]) +- [[`9202fe0308`](https://github.com/datrs/random-access-memory/commit/9202fe0308151dce780c7721f533bed2e11f7f3c)] Update quickcheck requirement from 0.6.2 to 0.7.1 (#6) (dependabot[bot]) +- [[`eae681682e`](https://github.com/datrs/random-access-memory/commit/eae681682eef6a4fe888f25b8728951873b6f114)] Run clippy on travis (#5) (Szabolcs Berecz) +- [[`df0755085c`](https://github.com/datrs/random-access-memory/commit/df0755085c1e472b084f9598aaa2ac0d4fb04f10)] update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 4 +++- + CHANGELOG.md | 20 ++++++++++++++++++++ + Cargo.toml | 7 ++++--- + src/lib.rs | 12 ++++++++++++ + tests/model.rs | 2 ++ + tests/test.rs | 18 ++++++++++++++++++ + 6 files changed, 59 insertions(+), 4 deletions(-) +``` + + +## 2018-08-30, Version 0.5.0 +### Commits +- [[`3baa7c2d23`](https://github.com/datrs/random-access-memory/commits/3baa7c2d23dfa774ac5e1d2b38bbb171eaf95bc0)] (cargo-release) version 0.5.0 (Yoshua Wuyts) +- [[`300ead96ab`](https://github.com/datrs/random-access-memory/commits/300ead96ab4eab5b66f786f3b0562ddb29571d27)] Random access always open (#4) (Szabolcs Berecz) +- [[`db908834f8`](https://github.com/datrs/random-access-memory/commits/db908834f8e79dd8a8f98a22e1403da3ebf458da)] update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 1 +- + CHANGELOG.md | 23 +++++++++++++++++- + Cargo.toml | 4 +-- + benches/sync.rs | 2 +- + src/lib.rs | 74 ++++++++++++++++++++++++------------------------------ + tests/model.rs | 2 +- + tests/regression.rs | 8 ++---- + tests/test.rs | 4 ++- + 8 files changed, 69 insertions(+), 49 deletions(-) +``` + + +## 2018-08-23, Version 0.4.0 +### Commits +- [[`7876a1a1ca`](https://github.com/datrs/random-access-memory/commits/7876a1a1ca10913a6126b767f4d07c3bae99dd8e)] (cargo-release) version 0.4.0 (Yoshua Wuyts) +- [[`cc83784775`](https://github.com/datrs/random-access-memory/commits/cc83784775a7cc737c97d514e88cdcb9ca2e718a)] upgrade random-access-storage (#3) + +* upgrade random-access-storage + +* cargo fmt (Yoshua Wuyts) +- [[`fae1a6509b`](https://github.com/datrs/random-access-memory/commits/fae1a6509b3c3825b3c063a627f64f85ab11cf40)] fix rustfmt in travis.yml (Yoshua Wuyts) +- [[`51c944434b`](https://github.com/datrs/random-access-memory/commits/51c944434b46c16ef7ba4028ac31ec10d6d64fe3)] fix benches (Yoshua Wuyts) +- [[`abfd505e04`](https://github.com/datrs/random-access-memory/commits/abfd505e049da526af068f475c1e8730e33238b9)] (cargo-release) start next development iteration 0.3.1-alpha.0 (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 2 +- + Cargo.toml | 4 ++-- + benches/sync.rs | 6 +++--- + src/lib.rs | 23 ++++++++++++++++------- + tests/regression.rs | 4 +--- + 5 files changed, 23 insertions(+), 16 deletions(-) +``` + + diff --git a/vendor/random-access-memory/Cargo.toml b/vendor/random-access-memory/Cargo.toml new file mode 100644 index 00000000..573f2b17 --- /dev/null +++ b/vendor/random-access-memory/Cargo.toml @@ -0,0 +1,50 @@ +# 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 = "random-access-memory" +version = "3.0.0" +authors = [ + "datrs ", + "Timo Tiuraniemi ", +] +description = "Continuously read and write to memory using random offsets and lengths" +documentation = "https://docs.rs/random-access-memory" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/datrs/random-access-memory" + +[[bench]] +name = "sync" +harness = false + +[dependencies.async-trait] +version = "0.1" + +[dependencies.intmap] +version = "2.0.0" + +[dependencies.random-access-storage] +version = "5.0.0" + +[dev-dependencies.async-std] +version = "1.12.0" +features = ["attributes"] + +[dev-dependencies.criterion] +version = "0.4" + +[dev-dependencies.proptest] +version = "1.1.0" + +[dev-dependencies.proptest-derive] +version = "0.2.0" diff --git a/vendor/random-access-memory/LICENSE-APACHE b/vendor/random-access-memory/LICENSE-APACHE new file mode 100644 index 00000000..6ab06963 --- /dev/null +++ b/vendor/random-access-memory/LICENSE-APACHE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018 Yoshua Wuyts + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/random-access-memory/LICENSE-MIT b/vendor/random-access-memory/LICENSE-MIT new file mode 100644 index 00000000..c7509bad --- /dev/null +++ b/vendor/random-access-memory/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Yoshua Wuyts + +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. diff --git a/vendor/random-access-memory/README.md b/vendor/random-access-memory/README.md new file mode 100644 index 00000000..86066f5d --- /dev/null +++ b/vendor/random-access-memory/README.md @@ -0,0 +1,27 @@ +# random-access-memory +[![crates.io version][1]][2] [![build status][3]][4] +[![downloads][5]][6] [![docs.rs docs][7]][8] + +Continuously read and write to memory using random offsets and lengths +using abstract interface defined in +[random-access-storage](https://github.com/datrs/random-access-storage). + +- [Documentation][8] +- [Crate][2] + +## Installation +```sh +$ cargo add random-access-memory +``` + +## License +[MIT](./LICENSE-MIT) OR [Apache-2.0](./LICENSE-APACHE) + +[1]: https://img.shields.io/crates/v/random-access-memory.svg?style=flat-square +[2]: https://crates.io/crates/random-access-memory +[3]: https://github.com/datrs/random-access-memory/actions/workflows/ci.yml/badge.svg +[4]: https://github.com/datrs/random-access-memory/actions[ +[5]: https://img.shields.io/crates/d/random-access-memory.svg?style=flat-square +[6]: https://crates.io/crates/random-access-memory +[7]: https://docs.rs/random-access-memory/badge.svg +[8]: https://docs.rs/random-access-memory diff --git a/vendor/random-access-memory/benches/sync.rs b/vendor/random-access-memory/benches/sync.rs new file mode 100644 index 00000000..1b5f5681 --- /dev/null +++ b/vendor/random-access-memory/benches/sync.rs @@ -0,0 +1,65 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use random_access_memory as ram; +use random_access_storage::RandomAccess; + +fn write_hello_world(c: &mut Criterion) { + c.bench_function("write hello world", |b| { + b.iter(|| { + async_std::task::block_on(async { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + }) + }) + }); +} + +fn read_hello_world(c: &mut Criterion) { + c.bench_function("read hello world", |b| { + async_std::task::block_on(async { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + b.iter(|| { + async_std::task::block_on(async { + let _text = file.read(0, 11).await.unwrap(); + }) + }); + }) + }); +} + +fn read_write_hello_world(c: &mut Criterion) { + c.bench_function("read/write hello world", |b| { + b.iter(|| { + async_std::task::block_on(async { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + let _text = file.read(0, 11).await.unwrap(); + }) + }) + }); +} + +fn write_del_hello_world(c: &mut Criterion) { + c.bench_function("write/del hello world", |b| { + b.iter(|| { + async_std::task::block_on(async { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello world").await.unwrap(); + file.del(0, 5).await.unwrap(); + file.del(5, 6).await.unwrap(); + }) + }) + }); +} + +criterion_group!( + benches, + write_hello_world, + read_hello_world, + read_write_hello_world, + write_del_hello_world, +); +criterion_main!(benches); diff --git a/vendor/random-access-memory/rustfmt.toml b/vendor/random-access-memory/rustfmt.toml new file mode 100644 index 00000000..4c1eefae --- /dev/null +++ b/vendor/random-access-memory/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 80 +tab_spaces = 2 diff --git a/vendor/random-access-memory/src/lib.rs b/vendor/random-access-memory/src/lib.rs new file mode 100644 index 00000000..f457bcee --- /dev/null +++ b/vendor/random-access-memory/src/lib.rs @@ -0,0 +1,335 @@ +#![forbid(unsafe_code, missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![doc(test(attr(deny(warnings))))] +//! # Continuously read and write to memory using random offsets and lengths +//! [RandomAccessMemory] is a complete implementation of [random-access-storage](https://docs.rs/random-access-storage) +//! for in-memory storage. +//! +//! See also [random-access-disk](https://docs.rs/random-access-disk) for on-disk storage +//! that can be swapped with this. +//! +//! ## Examples +//! +//! Reading, writing, deleting and truncating: +//! +//! ``` +//! # async_std::task::block_on(async { +//! use random_access_storage::RandomAccess; +//! use random_access_memory::RandomAccessMemory; +//! +//! let mut storage = RandomAccessMemory::default(); +//! storage.write(0, b"hello").await.unwrap(); +//! storage.write(5, b" world").await.unwrap(); +//! assert_eq!(storage.read(0, 11).await.unwrap(), b"hello world"); +//! assert_eq!(storage.len().await.unwrap(), 11); +//! storage.del(5, 2).await.unwrap(); +//! assert_eq!(storage.read(5, 2).await.unwrap(), [0, 0]); +//! assert_eq!(storage.len().await.unwrap(), 11); +//! storage.truncate(2).await.unwrap(); +//! assert_eq!(storage.len().await.unwrap(), 2); +//! storage.truncate(5).await.unwrap(); +//! assert_eq!(storage.len().await.unwrap(), 5); +//! assert_eq!(storage.read(0, 5).await.unwrap(), [b'h', b'e', 0, 0, 0]); +//! # }) +//! ``` +//! +//! In order to get benefits from the swappable interface, you will +//! in most cases want to use generic functions for storage manipulation: +//! +//! ``` +//! # async_std::task::block_on(async { +//! use random_access_storage::RandomAccess; +//! use random_access_memory::RandomAccessMemory; +//! use std::fmt::Debug; +//! +//! let mut storage = RandomAccessMemory::default(); +//! write_hello_world(&mut storage).await; +//! assert_eq!(read_hello_world(&mut storage).await, b"hello world"); +//! +//! /// Write with swappable storage +//! async fn write_hello_world(storage: &mut T) +//! where T: RandomAccess + Debug + Send, +//! { +//! storage.write(0, b"hello").await.unwrap(); +//! storage.write(5, b" world").await.unwrap(); +//! } +//! +//! /// Read with swappable storage +//! async fn read_hello_world(storage: &mut T) -> Vec +//! where T: RandomAccess + Debug + Send, +//! { +//! storage.read(0, 11).await.unwrap() +//! } +//! # }) +//! ``` + +pub use intmap::IntMap; + +use random_access_storage::{RandomAccess, RandomAccessError}; +use std::cmp; + +/// In-memory storage for random access +#[derive(Debug)] +pub struct RandomAccessMemory { + /// Length of each buffer + page_size: usize, + + /// Allocated memory + buffers: IntMap>, + + /// Total length of the data + length: u64, +} + +impl Default for RandomAccessMemory { + /// Create a new instance with a 1mb page size. + fn default() -> Self { + RandomAccessMemory::new(1024 * 1024) + } +} + +#[allow(clippy::needless_range_loop)] +impl RandomAccessMemory { + /// Create a new instance with `page_size` in bytes. + pub fn new(page_size: usize) -> Self { + RandomAccessMemory::with_buffers(page_size, IntMap::new()) + } + + /// Create a new instance with `page_size` in bytes, but pass the initial buffers to the constructor. + pub fn with_buffers(page_size: usize, buffers: IntMap>) -> Self { + RandomAccessMemory { + page_size, + buffers, + length: 0, + } + } + + /// Returns the page number and index within that page for a given offset. + /// If `exclusive_end` is true, when hitting the exact border of two pages + /// gives the previous page and page size as index. + fn page_num_and_index( + &self, + offset: u64, + exclusive_end: bool, + ) -> (usize, usize) { + let page_num = (offset / (self.page_size as u64)) as usize; + let page_index = (offset % (self.page_size as u64)) as usize; + if page_index == 0 && exclusive_end { + (if page_num > 0 { page_num - 1 } else { 0 }, self.page_size) + } else { + (page_num, page_index) + } + } + + /// Zero given range + fn zero(&mut self, offset: u64, length: u64) { + let (first_page_num, first_page_start) = + self.page_num_and_index(offset, false); + let (last_page_num, last_page_end) = + self.page_num_and_index(offset + length, true); + + // Check if we need to zero bytes in the first page + if first_page_start > 0 + || (first_page_num == last_page_num && last_page_end > 0) + { + if let Some(page) = self.buffers.get_mut(first_page_num as u64) { + // Need to zero part of the first page + let begin_page_end = first_page_start + + cmp::min(length as usize, self.page_size - first_page_start); + for index in first_page_start..begin_page_end { + page[index] = 0; + } + } + } + + // Delete intermediate pages + if last_page_num > first_page_num + 1 + || (first_page_start == 0 && last_page_num == first_page_num + 1) + { + let first_page_to_drop = if first_page_start == 0 { + first_page_num + } else { + first_page_num + 1 + }; + + for index in first_page_to_drop..last_page_num { + self.buffers.remove(index as u64); + } + } + + // Finally zero the last page + if last_page_num > first_page_num && last_page_end > 0 { + if let Some(page) = self.buffers.get_mut(last_page_num as u64) { + // Need to zero part of the final page + for index in 0..last_page_end { + page[index] = 0; + } + } + } + } +} + +#[async_trait::async_trait] +impl RandomAccess for RandomAccessMemory { + async fn write( + &mut self, + offset: u64, + data: &[u8], + ) -> Result<(), RandomAccessError> { + let new_len = offset + data.len() as u64; + if new_len > self.length { + self.length = new_len; + } + + let mut page_num = (offset / self.page_size as u64) as usize; + let mut page_cursor = + (offset - (page_num * self.page_size) as u64) as usize; + let mut data_cursor = 0; + + // Iterate over data, write to buffers. Subslice if the data is bigger than + // what we can write in a single go. + while data_cursor < data.len() { + let data_bound = data.len() - data_cursor; + let upper_bound = cmp::min(self.page_size, page_cursor + data_bound); + let range = page_cursor..upper_bound; + let range_len = (page_cursor..upper_bound).len(); + + // Allocate buffer if needed. Either append a new buffer to the end, or + // set a buffer in the center. + if self.buffers.get(page_num as u64).is_none() { + let buf = vec![0; self.page_size]; + self.buffers.insert(page_num as u64, buf); + } + + // Copy data from the vec slice. + // TODO: use a batch operation such as `.copy_from_slice()` so it can be + // optimized. + let buffer = &mut self.buffers.get_mut(page_num as u64).unwrap(); + for (index, buf_index) in range.enumerate() { + buffer[buf_index] = data[data_cursor + index]; + } + + page_num += 1; + page_cursor = 0; + data_cursor += range_len; + } + + Ok(()) + } + + async fn sync_all(&mut self) -> Result<(), RandomAccessError> { + Ok(()) + } + + async fn read( + &mut self, + offset: u64, + length: u64, + ) -> Result, RandomAccessError> { + if (offset + length) > self.length { + return Err(RandomAccessError::OutOfBounds { + offset, + end: Some(offset + length), + length: self.length, + }); + }; + + let mut page_num = (offset / self.page_size as u64) as usize; + let mut page_cursor = + (offset - (page_num * self.page_size) as u64) as usize; + + let mut res_buf = vec![0; length as usize]; + let mut res_cursor = 0; // Keep track we read the right amount of bytes. + let res_capacity = length; + + while res_cursor < res_capacity { + let res_bound = res_capacity - res_cursor; + let page_bound = self.page_size - page_cursor; + let relative_bound = cmp::min(res_bound, page_bound as u64); + let upper_bound = page_cursor + relative_bound as usize; + let range = page_cursor..upper_bound; + + // Fill until either we're done reading the page, or we're done + // filling the buffer. Whichever arrives sooner. + match self.buffers.get(page_num as u64) { + Some(buf) => { + for (index, buf_index) in range.enumerate() { + res_buf[res_cursor as usize + index] = buf[buf_index]; + } + } + None => { + for (index, _) in range.enumerate() { + res_buf[res_cursor as usize + index] = 0; + } + } + } + + res_cursor += relative_bound; + page_num += 1; + page_cursor = 0; + } + + Ok(res_buf) + } + + async fn del( + &mut self, + offset: u64, + length: u64, + ) -> Result<(), RandomAccessError> { + if offset > self.length { + return Err(RandomAccessError::OutOfBounds { + offset, + end: None, + length: self.length, + }); + }; + + if length == 0 { + // No-op + return Ok(()); + } + + // Delete is truncate if up to the current length or more is deleted + if offset + length >= self.length { + return self.truncate(offset).await; + } + + // Deleting means zeroing + self.zero(offset, length); + Ok(()) + } + + #[allow(clippy::comparison_chain)] + async fn truncate(&mut self, length: u64) -> Result<(), RandomAccessError> { + let (current_last_page_num, _) = self.page_num_and_index(self.length, true); + + if self.length < length { + let truncate_page_num = (length / self.page_size as u64) as usize; + // Remove all of the pages between the old length and this newer + // length that might have been left behind. + for index in current_last_page_num + 1..truncate_page_num + 1 { + self.buffers.remove(index as u64); + } + } else if self.length > length { + let delete_length = + ((current_last_page_num + 1) * self.page_size) - length as usize; + // Make sure to zero the remainder to not leave anything but + // zeros lying around. + self.zero(length, delete_length as u64); + } + + // Set new length + self.length = length; + + Ok(()) + } + + async fn len(&mut self) -> Result { + Ok(self.length) + } + + async fn is_empty(&mut self) -> Result { + Ok(self.length == 0) + } +} diff --git a/vendor/random-access-memory/tests/model.rs b/vendor/random-access-memory/tests/model.rs new file mode 100644 index 00000000..f2297757 --- /dev/null +++ b/vendor/random-access-memory/tests/model.rs @@ -0,0 +1,92 @@ +use self::Op::*; +use proptest::prelude::*; +use proptest::test_runner::FileFailurePersistence; +use proptest_derive::Arbitrary; +use random_access_memory as ram; +use random_access_storage::RandomAccess; +use std::u8; + +const MAX_FILE_SIZE: u64 = 50000; + +#[derive(Clone, Debug, Arbitrary)] +enum Op { + Read { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(strategy(offset_length_strategy))] + length: u64, + }, + Write { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(regex(data_regex))] + data: Vec, + }, + Delete { + #[proptest(strategy(offset_length_strategy))] + offset: u64, + #[proptest(strategy(offset_length_strategy))] + length: u64, + }, +} + +fn offset_length_strategy() -> impl Strategy { + 0..MAX_FILE_SIZE +} + +fn data_regex() -> &'static str { + // Write 0..5000 byte chunks of ASCII characters as dummy data + "([ -~]{1,1}\n){0,5000}" +} + +proptest! { + #![proptest_config(ProptestConfig { + failure_persistence: Some(Box::new(FileFailurePersistence::WithSource("regressions"))), + ..Default::default() + })] + + #[test] + fn implementation_matches_model(ops: Vec) { + assert!(async_std::task::block_on(async { + let mut implementation = ram::RandomAccessMemory::new(10); + let mut model = vec![]; + + for op in ops { + match op { + Read { offset, length } => { + let end = offset + length; + if model.len() >= end as usize { + assert_eq!( + &*implementation.read(offset, length).await.expect("Reads should be successful."), + &model[offset as usize..end as usize] + ); + } else { + assert!(implementation.read(offset, length).await.is_err()); + } + }, + Write { offset, ref data } => { + let end = offset + data.len() as u64; + if model.len() < end as usize { + model.resize(end as usize, 0); + } + implementation.write(offset, data).await.expect("Writes should be successful."); + model[offset as usize..end as usize].copy_from_slice(data); + }, + Delete { offset, length } => { + if model.len() >= offset as usize { + implementation.del(offset, length).await.expect("Deletes should be successful."); + if offset + length < model.len() as u64 { + model[offset as usize..(offset + length) as usize].fill(0); + } else { + model.resize(offset as usize, 0); + }; + } else { + assert!(implementation.del(offset, length).await.is_err()); + } + } + } + } + true + })); + } +} diff --git a/vendor/random-access-memory/tests/regression.rs b/vendor/random-access-memory/tests/regression.rs new file mode 100644 index 00000000..761c29dc --- /dev/null +++ b/vendor/random-access-memory/tests/regression.rs @@ -0,0 +1,47 @@ +use random_access_memory as ram; +use random_access_storage::RandomAccess; + +#[async_std::test] +// Postmortem: looks like we were reading out of bounds by accidentally +// adding an offset to the index while reading. +async fn regress_1() { + let mut file = ram::RandomAccessMemory::new(50); + file.write(30, &[30]).await.unwrap(); + file.read(15, 15).await.unwrap(); +} + +#[async_std::test] +// Postmortem: our buffers weren't zero-filled. Intead we were relying on +// uninitialized (but claimed!) memory, which caused all sorts of weirdness. +async fn regress_2() { + let mut file = ram::RandomAccessMemory::new(50); + file.write(22, &[22, 22, 22, 22]).await.unwrap(); + let buf = file.read(1, 4).await.unwrap(); + assert_eq!(buf, vec![0, 0, 0, 0]); + + let mut file = ram::RandomAccessMemory::new(50); + file.write(48, &[48, 48, 48, 48]).await.unwrap(); + let buf = file.read(39, 9).await.unwrap(); + assert_eq!(buf, vec![0, 0, 0, 0, 0, 0, 0, 0, 0]); +} + +#[async_std::test] +// Postmortem: the way we were reading was off. We were messing up both reading +// and writing. We now keep two cursors, and compute the bounds of every loop +// ahead of time. Also simplified our allocation logic. +async fn regress_3() { + let mut file = ram::RandomAccessMemory::new(50); + file.write(45, &[56, 46, 14, 93, 15, 54, 2]).await.unwrap(); + let buf = file.read(42, 10).await.unwrap(); + assert_eq!(buf, vec![0, 0, 0, 56, 46, 14, 93, 15, 54, 2]); +} + +#[async_std::test] +// Postmortem: we were having trouble when we were reading with an index that's +// larger than the page size. Turned out we weren't doing some math properly, +// which caused a cursor to jump. +async fn regress_4() { + let mut file = ram::RandomAccessMemory::new(10); + file.write(44, &[54, 59]).await.unwrap(); + file.read(13, 3).await.unwrap(); +} diff --git a/vendor/random-access-memory/tests/test.rs b/vendor/random-access-memory/tests/test.rs new file mode 100644 index 00000000..063dbdd3 --- /dev/null +++ b/vendor/random-access-memory/tests/test.rs @@ -0,0 +1,140 @@ +use random_access_memory as ram; +use random_access_storage::RandomAccess; + +#[async_std::test] +async fn can_call_new() { + let _file = ram::RandomAccessMemory::default(); +} + +#[async_std::test] +async fn can_open_buffer() { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); +} + +#[async_std::test] +async fn can_write() { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); +} + +#[async_std::test] +async fn can_read() { + let mut file = ram::RandomAccessMemory::default(); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + let text = file.read(0, 11).await.unwrap(); + let text = String::from_utf8(text.to_vec()).unwrap(); + assert_eq!(text, "hello world"); +} + +#[async_std::test] +async fn can_len() { + let mut file = ram::RandomAccessMemory::default(); + assert_eq!(file.len().await.unwrap(), 0); + file.write(0, b"hello").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 5); + file.write(5, b" world").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 11); +} + +#[async_std::test] +async fn can_is_empty() { + let mut file = ram::RandomAccessMemory::default(); + assert!(file.is_empty().await.unwrap()); + file.write(0, b"hello").await.unwrap(); + assert!(!file.is_empty().await.unwrap()); +} + +#[async_std::test] +async fn can_delete() { + assert_delete(100).await; + assert_delete(10).await; + assert_delete(5).await; + assert_delete(2).await; + assert_delete(1).await; +} + +async fn assert_delete(page_size: usize) { + let mut file = ram::RandomAccessMemory::new(page_size); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.write(11, b" people").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + file.del(6, 2).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + let text = file.read(0, 6).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello "); + let zeros = file.read(6, 2).await.unwrap(); + assert_eq!(zeros, [0, 0]); + let text = file.read(8, 10).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "rld people"); + file.del(8, 4).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + file.del(10, 8).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 10); +} + +#[async_std::test] +async fn can_truncate_lt() { + assert_truncate_lt(100).await; + assert_truncate_lt(10).await; + assert_truncate_lt(5).await; + assert_truncate_lt(2).await; + assert_truncate_lt(1).await; +} + +async fn assert_truncate_lt(page_size: usize) { + let mut file = ram::RandomAccessMemory::new(page_size); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.write(11, b" people").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + file.truncate(7).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 7); + let text = file.read(0, 7).await.unwrap(); + assert_eq!(String::from_utf8(text.to_vec()).unwrap(), "hello w"); + if file.read(0, 8).await.is_ok() { + panic!("storage is too big. read past the end should have failed"); + }; + file.write(11, b" people").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + let zeros = file.read(7, 4).await.unwrap(); + assert_eq!(zeros, [0, 0, 0, 0]); +} + +#[async_std::test] +async fn can_truncate_gt() { + assert_truncate_gt(100).await; + assert_truncate_gt(10).await; + assert_truncate_gt(5).await; + assert_truncate_gt(2).await; + assert_truncate_gt(1).await; +} + +async fn assert_truncate_gt(page_size: usize) { + let mut file = ram::RandomAccessMemory::new(page_size); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.write(11, b" people").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + file.truncate(22).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 22); + let zeros = file.read(18, 4).await.unwrap(); + assert_eq!(zeros, [0, 0, 0, 0]); + file.write(19, &[1]).await.unwrap(); + let written = file.read(18, 4).await.unwrap(); + assert_eq!(written, [0, 1, 0, 0]); +} + +#[async_std::test] +async fn assert_truncate_eq() { + let mut file = ram::RandomAccessMemory::new(5); + file.write(0, b"hello").await.unwrap(); + file.write(5, b" world").await.unwrap(); + file.write(11, b" people").await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); + file.truncate(18).await.unwrap(); + assert_eq!(file.len().await.unwrap(), 18); +} diff --git a/vendor/random-access-storage/.cargo-checksum.json b/vendor/random-access-storage/.cargo-checksum.json new file mode 100644 index 00000000..276e0aff --- /dev/null +++ b/vendor/random-access-storage/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CERTIFICATE":"53a0a460f8eccb279580aa16013c5f98936eba73554d267632f5ea83d8e890b1","CHANGELOG.md":"9117174bed864f1ee78f8628da9f594a1b7b900abef7be06eb63d1160e0ed69f","Cargo.toml":"f52f075a540d1c6ce3ca1e6676ba0d5295958f2a7e37a4ce3fe97da13c1ef78a","LICENSE-APACHE":"40b135370517318ee023f4553b49453ab716f4277ccc7801beb3a44ec481c9fb","LICENSE-MIT":"a06326997c80661a79a99f66af7417f3420640323952c92afae69d5a4b7537ee","README.md":"0986359997556cd5923612e97e20f738fbe75da93c03836fed0c8623c3a72df2","rustfmt.toml":"bd5701c9a978dcf1d7663447ca8aca21019a06cfe21f67863f459f80b8136f1a","src/lib.rs":"0f15f4591203455b8794bd9528691b54adbd72b7f3c2d6874f7d9c4e09e36445"},"package":"c5b3853b9ddec4adb53d5ee6ddc0ae8b552d2822cabb9120ae7d081721084393"} \ No newline at end of file diff --git a/vendor/random-access-storage/CERTIFICATE b/vendor/random-access-storage/CERTIFICATE new file mode 100644 index 00000000..8201f992 --- /dev/null +++ b/vendor/random-access-storage/CERTIFICATE @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/random-access-storage/CHANGELOG.md b/vendor/random-access-storage/CHANGELOG.md new file mode 100644 index 00000000..b54c0e4e --- /dev/null +++ b/vendor/random-access-storage/CHANGELOG.md @@ -0,0 +1,93 @@ +## 2020-03-03, Version 4.0.0 +### Commits +- [[`064eb1d6c9`](https://github.com/datrs/random-access-storage/commit/064eb1d6c9c1110f7cb01bfbaa6eb43d52330cd4)] (cargo-release) version 4.0.0 (Bruno Tavares) +- [[`0e7ab518e5`](https://github.com/datrs/random-access-storage/commit/0e7ab518e5d529160073e5aa295ff6a711472944)] Merge pull request #22 from bltavares/async-trait (Bruno Tavares) +- [[`2f5f4a0567`](https://github.com/datrs/random-access-storage/commit/2f5f4a0567db834f72afc6b75c512f309c9f4b13)] Github feedback: use futures-io to help with compile times (Bruno Tavares) +- [[`2bf3131775`](https://github.com/datrs/random-access-storage/commit/2bf31317753b242bedec37a0a6a576f5c26533c7)] Implement async API for random-access-storage (Bruno Tavares) +- [[`0bed19ef50`](https://github.com/datrs/random-access-storage/commit/0bed19ef50d0df238d0457e8af8890289ff385ed)] Merge pull request #20 from bltavares/master (Szabolcs Berecz) +- [[`831b9aa23e`](https://github.com/datrs/random-access-storage/commit/831b9aa23e72fbe38cf19c3c7c794d8acfe9099a)] Adjust Travis to run clippy and rustfmt on stable only (Bruno Tavares) +- [[`9c228739cc`](https://github.com/datrs/random-access-storage/commit/9c228739cc504d778b5c840d3d339dfbb54cae33)] Removes unused dependency (Bruno Tavares) +- [[`e0a1ea9880`](https://github.com/datrs/random-access-storage/commit/e0a1ea9880a42f48459763d30724badcbe274ac2)] Update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 8 ++++---- + CHANGELOG.md | 18 ++++++++++++++++++ + Cargo.toml | 6 ++++-- + README.md | 24 ++++++++++++------------ + src/lib.rs | 29 ++++++++++++++++++----------- + 5 files changed, 56 insertions(+), 29 deletions(-) +``` + + +## 2019-07-27, Version 3.0.0 +### Commits +- [[`49c25778a0`](https://github.com/datrs/random-access-storage/commit/49c25778a0f80db733028c059958303e374b5965)] (cargo-release) version 3.0.0 (Yoshua Wuyts) +- [[`553af611fd`](https://github.com/datrs/random-access-storage/commit/553af611fde9a22e92b17c9b52cc1379cd4dc57d)] u64 file offsets (#17) (James Halliday) +- [[`b73e7fb619`](https://github.com/datrs/random-access-storage/commit/b73e7fb619ebf07de6f5f409bee4f843cb0f0967)] sync_all method (#18) (James Halliday) +- [[`02e700d41c`](https://github.com/datrs/random-access-storage/commit/02e700d41ce119325d09c762b697b957af16697a)] Changed signature of len() to immutably borrow self (#19) (Freddie Ridell) +- [[`36c5b96d63`](https://github.com/datrs/random-access-storage/commit/36c5b96d63159317c6ec756ff579174e07856b10)] Update changelog (Yoshua Wuyts) + +### Stats +```diff + CHANGELOG.md | 16 ++++++++++++++++ + Cargo.toml | 4 ++-- + README.md | 4 ++++ + src/lib.rs | 21 ++++++++++----------- + 4 files changed, 32 insertions(+), 13 deletions(-) +``` + + +## 2018-12-18, Version 2.0.0 +### Commits +- [[`55ab88f0fd`](https://github.com/datrs/random-access-storage/commit/55ab88f0fd5114f8911442bc665fcca6949516ac)] (cargo-release) version 2.0.0 (Yoshua Wuyts) +- [[`81319ec100`](https://github.com/datrs/random-access-storage/commit/81319ec100e196c0ad79528d966d7717005c38f1)] len() and is_empty() (#16) (James Halliday) +- [[`fb18d9f5d3`](https://github.com/datrs/random-access-storage/commit/fb18d9f5d3a4b950f457d941acd69f6c57a11bf7)] Update changelog (Yoshua Wuyts) + +### Stats +```diff + CHANGELOG.md | 18 ++++++++++++++++++ + Cargo.toml | 2 +- + README.md | 8 ++++++++ + src/lib.rs | 8 ++++++++ + 4 files changed, 35 insertions(+), 1 deletion(-) +``` + + +## 2018-11-20, Version 1.0.0 +### Commits +- [[`2e9f4090d7`](https://github.com/datrs/random-access-storage/commit/2e9f4090d766a8fbaf6301e789b7db1439e383ad)] (cargo-release) version 1.0.0 (Yoshua Wuyts) +- [[`5e423e35ff`](https://github.com/datrs/random-access-storage/commit/5e423e35ff60ad7ed918a883c776c287a4b9b3fe)] truncate method (#15) (James Halliday) +- [[`0b242b6234`](https://github.com/datrs/random-access-storage/commit/0b242b6234586ceb1b23a2ac5a7ba5b021084be5)] Keep up with modern times in clippy invocation (#12) (Szabolcs Berecz) +- [[`622cf79c92`](https://github.com/datrs/random-access-storage/commit/622cf79c92194ea234c92bd090cd061425331ff0)] update changelog (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 2 +- + CHANGELOG.md | 19 +++++++++++++++++++ + Cargo.toml | 2 +- + README.md | 4 ++++ + src/lib.rs | 4 ++++ + 5 files changed, 29 insertions(+), 2 deletions(-) +``` + + +## 2018-08-29, Version 0.6.0 +### Commits +- [[`23e48f8e29`](https://github.com/datrs/random-access-storage/commits/23e48f8e29fc5cb0eaf7a0e77485cd6d23884771)] (cargo-release) version 0.6.0 (Yoshua Wuyts) +- [[`f1fc4982aa`](https://github.com/datrs/random-access-storage/commits/f1fc4982aa1f1a4e6b919344810f87ec36be36c7)] Fixes #7: Make RandomAccess always open (#11) (Szabolcs Berecz) +- [[`3855bef02a`](https://github.com/datrs/random-access-storage/commits/3855bef02a392bff362a297b610cdf9180f00ded)] Update README.md (#10) (周汉成) +- [[`97ebff543c`](https://github.com/datrs/random-access-storage/commits/97ebff543c466582f68c7dd192361dc41a9646dc)] add read_to_writer method (#9) (Yoshua Wuyts) +- [[`50b947e688`](https://github.com/datrs/random-access-storage/commits/50b947e688ef3ea5addd81991386ae389a66c1f6)] Fix typo and switch to clippy-preview (#5) (Szabolcs Berecz) +- [[`61a3d42a56`](https://github.com/datrs/random-access-storage/commits/61a3d42a56cfba8c0803854394f9488e68525085)] (cargo-release) start next development iteration 0.5.1-alpha.0 (Yoshua Wuyts) + +### Stats +```diff + .travis.yml | 2 +- + Cargo.toml | 2 +- + README.md | 23 +++++++++++++++------- + src/lib.rs | 66 ++++++++++---------------------------------------------------- + 4 files changed, 29 insertions(+), 64 deletions(-) +``` + + diff --git a/vendor/random-access-storage/Cargo.toml b/vendor/random-access-storage/Cargo.toml new file mode 100644 index 00000000..0c95e0fa --- /dev/null +++ b/vendor/random-access-storage/Cargo.toml @@ -0,0 +1,30 @@ +# 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 = "random-access-storage" +version = "5.0.0" +authors = [ + "Yoshua Wuyts ", + "Timo Tiuraniemi ", +] +description = "Abstract interface to implement random-access instances." +documentation = "https://docs.rs/random-access-storage" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/datrs/random-access-storage" + +[dependencies.async-trait] +version = "0.1" + +[dependencies.thiserror] +version = "1" diff --git a/vendor/random-access-storage/LICENSE-APACHE b/vendor/random-access-storage/LICENSE-APACHE new file mode 100644 index 00000000..6ab06963 --- /dev/null +++ b/vendor/random-access-storage/LICENSE-APACHE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018 Yoshua Wuyts + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/random-access-storage/LICENSE-MIT b/vendor/random-access-storage/LICENSE-MIT new file mode 100644 index 00000000..c7509bad --- /dev/null +++ b/vendor/random-access-storage/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Yoshua Wuyts + +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. diff --git a/vendor/random-access-storage/README.md b/vendor/random-access-storage/README.md new file mode 100644 index 00000000..0aa2dc2e --- /dev/null +++ b/vendor/random-access-storage/README.md @@ -0,0 +1,28 @@ +# random-access-storage +[![crates.io version][1]][2] [![build status][3]][4] +[![downloads][5]][6] [![docs.rs docs][7]][8] + +Abstract interface to implement random-access instances. + +- [Documentation][8] +- [Crate][2] + +## Installation +```sh +$ cargo add random-access-storage +``` + +## See Also +- Original Javascript [random-access-storage](https://github.com/random-access-storage/random-access-storage) + +## License +[MIT](./LICENSE-MIT) OR [Apache-2.0](./LICENSE-APACHE) + +[1]: https://img.shields.io/crates/v/random-access-storage.svg?style=flat-square +[2]: https://crates.io/crate/random-access-storage +[3]: https://github.com/datrs/random-access-storage/actions/workflows/ci.yml/badge.svg +[4]: https://github.com/datrs/random-access-storage/actions +[5]: https://img.shields.io/crates/d/random-access-storage.svg?style=flat-square +[6]: https://crates.io/crates/random-access-storage +[7]: https://docs.rs/random-access-storage/badge.svg +[8]: https://docs.rs/random-access-storage diff --git a/vendor/random-access-storage/rustfmt.toml b/vendor/random-access-storage/rustfmt.toml new file mode 100644 index 00000000..4c1eefae --- /dev/null +++ b/vendor/random-access-storage/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 80 +tab_spaces = 2 diff --git a/vendor/random-access-storage/src/lib.rs b/vendor/random-access-storage/src/lib.rs new file mode 100644 index 00000000..fea5037e --- /dev/null +++ b/vendor/random-access-storage/src/lib.rs @@ -0,0 +1,186 @@ +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![doc(test(attr(deny(warnings))))] +//! # Abstract interface to implement random-access instances +//! +//! This crate defines the shared [RandomAccess] trait that makes it possible to create +//! different backends for reading, writing and deleting bytes. With a shared interface, +//! implementations can easily be swapped, depending on the needs and the environment. +//! +//! ## Known Implementations +//! +//! Full implementations of [RandomAccess] include: +//! +//! * [random-access-memory](https://docs.rs/random-access-memory) for in-memory storage +//! * [random-access-disk](https://docs.rs/random-access-disk) for disk storage +//! +//! ## Examples +//! +//! Your own random-access backend can be implemented like this: +//! +//! ``` +//! use random_access_storage::{RandomAccess, RandomAccessError}; +//! use async_trait::async_trait; +//! +//! struct MyRandomAccess { +//! // Add fields here +//! } +//! +//! #[async_trait] +//! impl RandomAccess for MyRandomAccess { +//! async fn write(&mut self, _offset: u64, _data: &[u8]) -> Result<(), RandomAccessError> { +//! unimplemented!(); +//! } +// +//! async fn read(&mut self, _offset: u64, _length: u64) -> Result, RandomAccessError> { +//! unimplemented!(); +//! } +//! +//! async fn del(&mut self, _offset: u64, _length: u64) -> Result<(), RandomAccessError> { +//! unimplemented!(); +//! } +//! +//! async fn truncate(&mut self, _length: u64) -> Result<(), RandomAccessError> { +//! unimplemented!(); +//! } +//! +//! async fn len(&mut self) -> Result { +//! unimplemented!(); +//! } +//! +//! async fn is_empty(&mut self) -> Result { +//! unimplemented!(); +//! } +//! +//! async fn sync_all(&mut self) -> Result<(), RandomAccessError> { +//! unimplemented!(); +//! } +//! } +//! ``` +use thiserror::Error; + +/// Error type for the [RandomAccess] trait methods. +#[derive(Error, Debug)] +pub enum RandomAccessError { + /// Given parameters are out of bounds. + #[error("{} out of bounds. {} < {}{}", + .end.as_ref().map_or_else(|| "Offset", |_| "Range"), + .length, + .offset, + .end.as_ref().map_or_else(String::new, |end| format!("..{}", end)))] + OutOfBounds { + /// Offset that was out of bounds + offset: u64, + /// If it was a range that was out of bounds, the end of the range. + end: Option, + /// The length in the implementation that was exceeded. + length: u64, + }, + /// Unexpected [std::io::Error]. + #[error("Unrecoverable input/output error occured.{}{}", + .return_code.as_ref().map_or_else(String::new, |rc| format!(" Return code: {}.", rc)), + .context.as_ref().map_or_else(String::new, |ctx| format!(" Context: {}.", ctx)))] + IO { + /// Optional system return code that caused the error. + return_code: Option, + /// Optional context of the error. + context: Option, + /// Source of the error. + #[source] + source: std::io::Error, + }, +} + +impl From for RandomAccessError { + fn from(err: std::io::Error) -> Self { + Self::IO { + return_code: None, + context: None, + source: err, + } + } +} + +/// Interface for reading from, writing to and deleting from a +/// randomly accessible storage of bytes. +#[async_trait::async_trait] +pub trait RandomAccess { + /// Write bytes of `data` at an `offset` to the backend. + /// + /// # Errors + /// + /// * [RandomAccessError::OutOfBounds] if the backend has + /// a maximum capacity that would be exceeded by the write. + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn write( + &mut self, + offset: u64, + data: &[u8], + ) -> Result<(), RandomAccessError>; + + /// Read a sequence of bytes at an `offset` from the backend. + /// + /// # Errors + /// + /// * [RandomAccessError::OutOfBounds] if + /// [RandomAccess::len] > `offset` + `length`. + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn read( + &mut self, + offset: u64, + length: u64, + ) -> Result, RandomAccessError>; + + /// Delete a sequence of bytes of given `length` at an `offset` from the backend. + /// This either sets the bytes in the given slice to zeroes, or if + /// `offset` + `length` >= [RandomAccess::len()] is the same as + /// `truncate(offset)`. + /// + /// # Errors + /// + /// * [RandomAccessError::OutOfBounds] if [RandomAccess::len()] < `offset` + `length`. + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn del( + &mut self, + offset: u64, + length: u64, + ) -> Result<(), RandomAccessError>; + + /// Resize the sequence of bytes so that [RandomAccess::len()] is set to + /// `length`. If `length` < [RandomAccess::len()], the bytes are disregarded. + /// If `length` > [RandomAccess::len()], the storage is zero-padded. + /// + /// # Errors + /// + /// * [RandomAccessError::OutOfBounds] if the backend has + /// a maximum capacity smaller than `length`. + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn truncate(&mut self, length: u64) -> Result<(), RandomAccessError>; + + /// Get the size of the storage in bytes. + /// + /// # Errors + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn len(&mut self) -> Result; + + /// Whether the storage is empty. For some storage backends it may be + /// cheaper to calculate whether the storage is empty than to calculate the + /// length. + /// + /// # Errors + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn is_empty(&mut self) -> Result; + + /// Flush buffered data on the underlying storage resource. + /// + /// # Errors + /// + /// * [RandomAccessError::IO] if an unexpected IO error occurred. + async fn sync_all(&mut self) -> Result<(), RandomAccessError>; +}