1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! The [lockable](https://crates.io/crates/lockable) library offers thread-safe
//! HashMap (see [LockableHashMap](crate::lockable_hash_map::LockableHashMap)),
//! LruCache (see [LockableLruCache](crate::lockable_lru_cache::LockableLruCache))
//! and LockPool (see [LockPool](crate::lockpool::LockPool)) types. In all of these
//! dat atypes, individual keys can be locked/unlocked, even if there is no entry
//! for this key in the map or cache.
//!
//! This can be very useful for synchronizing access to an underlying key-value
//! store or for building cache data structures on top of such a key-value store.
//!
//! ## LRU cache example
//! This example builds a simple LRU cache and locks some entries.
//! ```
#![cfg_attr(
not(feature = "lru"),
doc = "```
```ignore"
)]
//! use lockable::{AsyncLimit, LockableLruCache};
//!
//! let lockable_cache = LockableLruCache::<i64, String>::new();
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//!
//! // Insert an entry
//! lockable_cache.async_lock(4, AsyncLimit::no_limit())
//! .await?
//! .insert(String::from("Value"));
//!
//! // Hold a lock on a different entry
//! let guard = lockable_cache.async_lock(5, AsyncLimit::no_limit())
//! .await?;
//!
//! // This next line would wait until the lock gets released,
//! // which in this case would cause a deadlock because we're
//! // on the same thread
//! // let guard2 = lockable_cache.async_lock(5, AsyncLimit::no_limit())
//! // .await?;
//!
//! // After dropping the corresponding guard, we can lock it again
//! std::mem::drop(guard);
//! let guard2 = lockable_cache.async_lock(5, AsyncLimit::no_limit())
//! .await?;
//! # Ok::<(), lockable::Never>(())}).unwrap();
//! ```
//!
//! ## Lockpool example
//! This example builds a simple lock pool using the [LockPool](crate::lockpool::LockPool)
//! data structure. A lock pool is a pool of keyable locks. This can be used if
//! you don't need a cache but just some way to synchronize access to an underlying
//! resource.
//! ```
//! use lockable::LockPool;
//!
//! let lockpool = LockPool::new();
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! let guard1 = lockpool.async_lock(4).await;
//! let guard2 = lockpool.async_lock(5).await;
//!
//! // This next line would wait until the lock gets released,
//! // which in this case would cause a deadlock because we're
//! // on the same thread.
//! // let guard3 = lockpool.async_lock(4).await;
//!
//! // After dropping the corresponding guard, we can lock it again
//! std::mem::drop(guard1);
//! let guard3 = lockpool.async_lock(4).await;
//! # Ok::<(), lockable::Never>(())}).unwrap();
//! ```
//!
//! ## HashMap example
//! If you need a lockable key-value store but don't need the LRU ordering,
//! you can use [LockableHashMap](crate::lockable_hash_map::LockableHashMap).
//! ```
//! use lockable::{AsyncLimit, LockableHashMap};
//!
//! let lockable_map = LockableHashMap::<i64, String>::new();
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//!
//! // Insert an entry
//! lockable_map.async_lock(4, AsyncLimit::no_limit())
//! .await?
//! .insert(String::from("Value"));
//!
//! // Hold a lock on a different entry
//! let guard = lockable_map.async_lock(5, AsyncLimit::no_limit())
//! .await?;
//!
//! // This next line would wait until the lock gets released,
//! // which in this case would cause a deadlock because we're
//! // on the same thread
//! // let guard2 = lockable_map.async_lock(5, AsyncLimit::no_limit())
//! // .await?;
//!
//! // After dropping the corresponding guard, we can lock it again
//! std::mem::drop(guard);
//! let guard2 = lockable_map.async_lock(5, AsyncLimit::no_limit())
//! .await?;
//! # Ok::<(), lockable::Never>(())}).unwrap();
//! ```
//!
//! ## Crate Features
//! - `lru`: Enables the [LockableLruCache](crate::lockable_lru_cache::LockableLruCache)
//! type which adds a dependency on the [lru](https://crates.io/crates/lru) crate.
// TODO Figure out which functions actually should or shouldn't be #[inline]
#![forbid(unsafe_code)]
#![deny(missing_docs)]
// We need to add explicit links because our `gen_readme.sh` script requires them.
#![allow(rustdoc::redundant_explicit_links)]
mod guard;
mod hooks;
mod limit;
mod lockable_map_impl;
mod lockable_trait;
mod map_like;
mod utils;
#[cfg(test)]
mod tests;
mod lockable_hash_map;
#[cfg(feature = "lru")]
mod lockable_lru_cache;
mod lockpool;
pub use guard::{Guard, TryInsertError};
pub use limit::{AsyncLimit, SyncLimit};
pub use lockable_hash_map::LockableHashMap;
#[cfg(feature = "lru")]
pub use lockable_lru_cache::LockableLruCache;
pub use lockable_trait::Lockable;
pub use lockpool::LockPool;
pub use utils::never::{InfallibleUnwrap, Never};