cacache/lib.rs
1//! cacache is a Rust library for managing local key and content address
2//! caches. It's really fast, really good at concurrency, and it will never
3//! give you corrupted data, even if cache files get corrupted or manipulated.
4//!
5//! ## API Layout
6//!
7//! The cacache API is organized roughly similar to `std::fs`; most of the
8//! toplevel functionality is available as free functions directly in the
9//! `cacache` module, with some additional functionality available through
10//! returned objects, as well as `WriteOpts`, which is analogous to
11//! `OpenOpts`, but is only able to write.
12//!
13//! One major difference is that the default APIs are all async functions, as
14//! opposed to `std::fs`, where they're all synchronous. Synchronous APIs in
15//! cacache are accessible through the `_sync` suffix.
16//!
17//! ### Suffixes
18//!
19//! You may notice various suffixes associated with otherwise familiar
20//! functions:
21//!
22//! * `_sync` - Most cacache APIs are asynchronous by default. Anything using
23//! the `_sync` suffix behaves just like its unprefixed counterpart, except
24//! the operation is synchronous.
25//! * `_hash` - Since cacache is a content-addressable cache, the `_hash`
26//! suffix means you're interacting directly with content data, skipping the
27//! index and its metadata. These functions use an `Integrity` to look up
28//! data, instead of a string key.
29//!
30//! ## Examples
31//!
32//! Un-suffixed APIs are all async, using
33//! [`async-std`](https://crates.io/crates/async-std). They let you put data
34//! in and get it back out -- asynchronously!
35//!
36//! ```no_run
37//! use async_attributes;
38//!
39//! #[async_attributes::main]
40//! async fn main() -> cacache::Result<()> {
41//! // Data goes in...
42//! cacache::write("./my-cache", "key", b"hello").await?;
43//!
44//! // ...data comes out!
45//! let data = cacache::read("./my-cache", "key").await?;
46//! assert_eq!(data, b"hello");
47//!
48//! Ok(())
49//! }
50//! ```
51//!
52//! ### Lookup by hash
53//!
54//! What makes `cacache` content addressable, though, is its ability to fetch
55//! data by its "content address", which in our case is a ["subresource
56//! integrity" hash](https://crates.io/crates/ssri), which `cacache::put`
57//! conveniently returns for us. Fetching data by hash is significantly faster
58//! than doing key lookups:
59//!
60//! ```no_run
61//! use async_attributes;
62//!
63//! #[async_attributes::main]
64//! async fn main() -> cacache::Result<()> {
65//! // Data goes in...
66//! let sri = cacache::write("./my-cache", "key", b"hello").await?;
67//!
68//! // ...data gets looked up by `sri` ("Subresource Integrity").
69//! let data = cacache::read_hash("./my-cache", &sri).await?;
70//! assert_eq!(data, b"hello");
71//!
72//! Ok(())
73//! }
74//! ```
75//!
76//! ### Large file support
77//!
78//! `cacache` supports large file reads, in both async and sync mode, through
79//! an API reminiscent of `std::fs::OpenOptions`:
80//!
81//! ```no_run
82//! use async_attributes;
83//! use async_std::prelude::*;
84//!
85//! #[async_attributes::main]
86//! async fn main() -> cacache::Result<()> {
87//! let mut fd = cacache::Writer::create("./my-cache", "key").await?;
88//! for _ in 0..10 {
89//! fd.write_all(b"very large data").await.expect("Failed to write to cache");
90//! }
91//! // Data is only committed to the cache after you do `fd.commit()`!
92//! let sri = fd.commit().await?;
93//! println!("integrity: {}", &sri);
94//!
95//! let mut fd = cacache::Reader::open("./my-cache", "key").await?;
96//! let mut buf = String::new();
97//! fd.read_to_string(&mut buf).await.expect("Failed to read to string");
98//!
99//! // Make sure to call `.check()` when you're done! It makes sure that what
100//! // you just read is actually valid. `cacache` always verifies the data
101//! // you get out is what it's supposed to be. The check is very cheap!
102//! fd.check()?;
103//!
104//! Ok(())
105//! }
106//! ```
107//!
108//! ### Sync API
109//!
110//! There are also sync APIs available if you don't want to use async/await.
111//! The synchronous APIs are generally faster for linear operations -- that
112//! is, doing one thing after another, as opposed to doing many things at
113//! once. If you're only reading and writing one thing at a time across your
114//! application, you probably want to use these instead.
115//!
116//! If you wish to _only_ use sync APIs and not pull in an async runtime, you
117//! can disable default features:
118//!
119//! ```toml
120//! # Cargo.toml
121//! [dependencies]
122//! cacache = { version = "X.Y.Z", default-features = false, features = ["mmap"] }
123//! ```
124//!
125//! ```no_run
126//! fn main() -> cacache::Result<()> {
127//! cacache::write_sync("./my-cache", "key", b"my-data").unwrap();
128//! let data = cacache::read_sync("./my-cache", "key").unwrap();
129//! assert_eq!(data, b"my-data");
130//! Ok(())
131//! }
132//! ```
133//!
134//! ### Linking to existing files
135//!
136//! The `link_to` feature enables an additional set of APIs for adding
137//! existing files into the cache via symlinks, without having to duplicate
138//! their data. Once the cache links to them, these files can be accessed by
139//! key just like other cached data, with the same integrity checking.
140//!
141//! The `link_to` methods are available in both async and sync variants, using
142//! the same suffixes as the other APIs.
143//!
144//! ```no_run
145//! #[async_attributes::main]
146//! async fn main() -> cacache::Result<()> {
147//! #[cfg(feature = "link_to")]
148//! cacache::link_to("./my-cache", "key", "/path/to/my-other-file.txt").await?;
149//! let data = cacache::read("./my-cache", "key").await?;
150//! assert_eq!(data, b"my-data");
151//! Ok(())
152//! }
153//! ```
154#![warn(missing_docs)]
155
156#[cfg(all(feature = "async-std", feature = "tokio-runtime"))]
157compile_error!("Only either feature \"async-std\" or \"tokio-runtime\" must be enabled for this crate, not both.");
158
159pub use serde_json::Value;
160pub use ssri::{Algorithm, Integrity};
161
162#[cfg(any(feature = "async-std", feature = "tokio"))]
163mod async_lib;
164
165mod content;
166mod errors;
167pub mod index;
168
169mod get;
170#[cfg(feature = "link_to")]
171mod linkto;
172mod ls;
173mod put;
174mod rm;
175
176pub use errors::{Error, Result};
177pub use index::{Metadata, RemoveOpts};
178
179pub use get::*;
180#[cfg(feature = "link_to")]
181pub use linkto::*;
182pub use ls::*;
183pub use put::*;
184pub use rm::*;