diff --git a/Cargo.lock b/Cargo.lock index b540f92..d1269d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,15 @@ dependencies = [ "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "async-attributes" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "async-macros" version = "1.0.0" @@ -163,6 +172,7 @@ dependencies = [ name = "cacache" version = "2.0.1" dependencies = [ + "async-attributes 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "async-std 0.99.9 (registry+https://github.com/rust-lang/crates.io-index)", "chownr 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1073,6 +1083,7 @@ dependencies = [ [metadata] "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum async-attributes 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5266d863e013ece9c8793b69fe6d3a70679f7adea32c92d0aa5eb6e2a55d4d06" "checksum async-macros 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e421d59b24c1feea2496e409b3e0a8de23e5fc130a2ddc0b012e551f3b272bba" "checksum async-std 0.99.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e274b0689dffa49d9c128a7bd1a86707b6bc8ea319af0899caae654e221656f4" "checksum async-task 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de6bd58f7b9cc49032559422595c81cbfcf04db2f2133592f70af19e258a1ced" diff --git a/Cargo.toml b/Cargo.toml index e7b3364..58a5b7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ chownr = "2.0.0" nix = "0.14.0" [dev-dependencies] +async-attributes = "1.0.0" criterion = "0.2.11" [[bench]] diff --git a/src/lib.rs b/src/lib.rs index f924cd7..ad8432b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,29 +3,94 @@ //! give you corrupted data, even if cache files get corrupted or manipulated. //! //! ## Examples -//! ``` -//! use tempfile; -//! use cacache; -//! use async_std::task; //! -//! let tmp = tempfile::tempdir().unwrap(); -//! let dir = tmp.path().to_owned(); -//! task::block_on(async { -//! cacache::put::data(&dir, "key", b"my-async-data").await.unwrap(); -//! let data = cacache::get::data(&dir, "key").await.unwrap(); -//! assert_eq!(data, b"my-async-data"); -//! }) +//! Un-suffixed APIs are all async, using +//! [`async-std`](https://crates.io/crates/async-std). They let you put data +//! in and get it back out -- asynchronously! +//! +//! ```no_run +//! use async_attributes; +//! +//! #[async_attributes::main] +//! async fn main() -> Result<(), cacache::Error> { +//! // Data goes in... +//! cacache::put::data("./my-cache", "key", b"hello").await?; +//! +//! // ...data comes out! +//! let data = cacache::get::data("./my-cache", "key").await?; +//! assert_eq!(data, b"hello"); +//! +//! Ok(()) +//! } //! ``` //! +//! ### Lookup by hash +//! +//! What makes `cacache` content addressable, though, is its ability to fetch +//! data by its "content address", which in our case is a ["subresource +//! integrity" hash](https://crates.io/crates/ssri), which `cacache::put` +//! conveniently returns for us. Fetching data by hash is significantly faster +//! than doing key lookups: +//! +//! ```no_run +//! use async_attributes; +//! +//! #[async_attributes::main] +//! async fn main() -> Result<(), cacache::Error> { +//! // Data goes in... +//! let sri = cacache::put::data("./my-cache", "key", b"hello").await?; +//! +//! // ...data gets looked up by `sri` ("Subresource Integrity"). +//! let data = cacache::get::data_hash("./my-cache", &sri).await?; +//! assert_eq!(data, b"hello"); +//! +//! Ok(()) +//! } +//! ``` +//! +//! ### Large file support +//! +//! `cacache` supports large file reads, in both async and sync mode, through +//! an API reminiscent of `std::fs::OpenOptions`: +//! +//! ```no_run +//! use async_attributes; +//! use async_std::prelude::*; +//! +//! #[async_attributes::main] +//! async fn main() -> Result<(), cacache::Error> { +//! let mut fd = cacache::put::PutOpts::new().open("./my-cache", "key").await?; +//! for _ in 0..10 { +//! fd.write_all(b"very large data").await?; +//! } +//! // Data is only persisted to the cache after you do `fd.commit()`! +//! let sri = fd.commit().await?; +//! println!("integrity: {}", &sri); +//! +//! let mut fd = cacache::get::open("./my-cache", "key").await?; +//! let mut buf = String::new(); +//! fd.read_to_string(&mut buf).await?; +//! +//! // Make sure to call `.check()` when you're done! It makes sure that what +//! // you just read is actually valid. `cacache` always verifies the data +//! // you get out is what it's supposed to be. The check is very cheap! +//! fd.check()?; +//! +//! Ok(()) +//! } +//! ``` +//! +//! ### Sync API +//! //! There are also sync APIs available if you don't want to use async/await: -//! ``` -//! use cacache; -//! # use tempfile; -//! # let tmp = tempfile::tempdir().unwrap(); -//! let dir = tmp.path().to_owned(); -//! cacache::put::data_sync(&dir, "key", b"my-data").unwrap(); -//! let data = cacache::get::data_sync(&dir, "key").unwrap(); -//! assert_eq!(data, b"my-data"); +//! +//! ```no_run +//! fn main() -> Result<(), cacache::Error> { +//! cacache::put::data_sync("./my-cache", "key", b"my-data").unwrap(); +//! let data = cacache::get::data_sync("./my-cache", "key").unwrap(); +//! assert_eq!(data, b"my-data"); +//! Ok(()) +//! } //! ``` #![warn(missing_docs, missing_doc_code_examples)]