pub struct Store<K, T> where
    K: Key,
    T: Serialize + DeserializeOwned
{ /* private fields */ }

Implementations

Allocates a new Store containing no values. Opens a file descriptor to path.

Reads the header and checks to see whether or not the store is valid; at this time, this means making sure the format is fully up-to-date and writing completed.

Provides a sequential stream of all values in the Store. In relational database parlance, this would be a tablescan.

Looks up a single value by key. Will attempt to cache data positions in the backing file to minimize disk seeking. Returns Error::NotFound when key does not exist in the Store.

Looks up multiple values by key. Will find (uncached) keys in sorted order to minimize disk seeking back and forth. Does not return an error when key does not exist; calling code should check for Some vs None in the resulting HashMap for fallibility.

Consumes a TryStream of (key, value) pairs. Sequentially writes all the values to disk, noting their positions, then goes back and sequentially writes down the sorted index.

Making effective use of this error handling mechanism is complex; an example is included below.

The Error type is usually inferrable. A recommended pattern is to have it be your crate’s Error type, or anyhow::Error.

index_size_hint is used to preallocate the in-memory index that is eventually written to disk, which is strictly a performance optimization. If it’s unknown, passing a 0 is fine.

Example:

use std::io;
use futures::TryStreamExt;
use indexkv::{Store, StreamError};

#[derive(Debug, thiserror::Error)]
enum MyError {
	#[error("I/O error")]
	IO(#[from] io::Error),
	#[error("cache error")]
	Cache(#[from] indexkv::Error<u64>)
}

impl From<StreamError<MyError, u64>> for MyError {
	fn from(other: StreamError<MyError, u64>) -> Self {
		match other {
			StreamError::Caller(e) => e,
			StreamError::Internal(e) => MyError::from(e)
		}
	}
}

async fn write() -> Result<(), MyError> {
	let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
	let mut store: Store<u64, String> = Store::new(path).await.unwrap();

	let stream = futures::stream::iter(
		vec![Ok("zero"), Ok("one"), Err(io::Error::from(io::ErrorKind::BrokenPipe)), Ok("two")]
			.into_iter()
			.enumerate()
			.map(|(i, r)| match r {
				Ok(v) => Ok((i as u64, v.to_string())),
				Err(e) => Err(e)
			})
	).err_into::<MyError>();
	store.write(stream, 0).await?;
	Ok(())
}

#[tokio::main]
async fn main() {
	let result = write().await;
	assert!(matches!(
		result,
		Err(MyError::IO(_))
	));
}

For cases where the incoming data stream is infallible, this allows you to avoid that portion of error handling.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more

Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more