Crate tote[−][src]
Expand description
Tote
A lightweight data file cache for CLI libraries
For CLIs that query a default set of information with each invocation,
Tote
offers a convenient way to cache data to a file for quicker
subsequent CLI runs.
When Tote
is used for a cache (examples below), the tote.get()
call will:
- Check that the
Tote
filepath exists and has been modified within the specified expiry time - Deserialize and return the data
If the cached data is not present or expired, Tote
will:
- Use the
Fetch::fetch
methods to retrieve the data - Serialize the data (using
serde_json
) and write to theTote
filepath - Return the newly fetched data
Features
Default
The default feature uses a Synchronous Fetch
trait:
use std::time::Duration;
use serde_derive::{Serialize, Deserialize};
use tote::{Fetch, Tote};
// Implement `serde`'s `Serialize`/`Deserialize` for you own data
// or make a NewType and `derive` so `Tote` can read and write the cached data
#[derive(Debug, Deserialize, Serialize)]
struct MyData(Vec<String>);
impl Fetch<MyData> for MyData {
fn fetch() -> Result<MyData, Box<dyn std::error::Error>> {
// This would likely do some I/O to fetch common data
Ok(MyData(vec!["Larkspur".to_owned(), "Lavender".to_owned(), "Periwinkle".to_owned()]))
}
}
fn main () -> Result<(), Box<dyn std::error::Error>> {
// Create a Tote at the given path, with data expiry of 1 day
let cache: Tote<MyData> = Tote::new(".my_tool.cache", Duration::from_secs(86400));
// This `.get()` call will use data cached in ".my_tool.cache" if:
// - The file exists & has valid data
// - The file has been modified in the past 1 day
// Otherwise `MyData::fetch` is called to get the data and populate the cache file
let available_colors = cache.get()?;
println!("Colors you can use are: {:?}", available_colors);
Ok(())
}
Async
The "async"
feature adds the AsyncFetch
trait if you want to use async I/O for fetching data. Call Tote::get_async().await
to get the Tote
contents.
Cargo.toml
tote = { version = "*", features = ["async"] }
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::Duration;
use async_trait::async_trait;
use serde_derive::{Serialize, Deserialize};
use tote::{AsyncFetch, Tote};
// Implement `serde`'s `Serialize`/`Deserialize` for you own data
// or make a NewType and `derive` so `Tote` can read and write the cached data
#[derive(Debug, Deserialize, Serialize)]
struct MyData(IpAddr);
#[async_trait]
impl AsyncFetch<MyData> for MyData {
async fn fetch_async() -> Result<MyData, Box<dyn std::error::Error>> {
let resp = reqwest::get("https://httpbin.org/ip")
.await?
.json::<HashMap<String, String>>()
.await?;
let origin_ip = resp["origin"].parse()?;
Ok(MyData(origin_ip))
}
}
#[tokio::main]
async fn main () -> Result<(), Box<dyn std::error::Error>> {
// Create a Tote at the given path, with data expiry of 1 day
let cache: Tote<MyData> = Tote::new(".my_tool.cache", Duration::from_secs(86400));
// This `.get_async().await` call will use data cached in ".my_tool.cache" if:
// - The file exists & has valid data
// - The file has been modified in the past 1 day
// Otherwise `MyData::fetch_async` is called to get the data and populate the cache file
let public_ip = cache.get_async().await?;
println!("Your public IP address is {}", public_ip.0);
Ok(())
}
Structs
Local file cache for D42 device info
Enums
Errors that can occur during Tote
operations
Traits
A trait provided to allow Tote
to fetch the data
when no cache exists or cache is expired