{"id":13503881,"url":"https://github.com/moka-rs/moka","last_synced_at":"2026-01-26T02:17:39.175Z","repository":{"id":37036636,"uuid":"253290187","full_name":"moka-rs/moka","owner":"moka-rs","description":"A high performance concurrent caching library for Rust","archived":false,"fork":false,"pushed_at":"2025-05-08T22:54:43.000Z","size":3122,"stargazers_count":1930,"open_issues_count":45,"forks_count":81,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-11T03:49:31.630Z","etag":null,"topics":["cache","concurrent-data-structure"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moka-rs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"tatsuya6502"}},"created_at":"2020-04-05T17:18:18.000Z","updated_at":"2025-05-10T14:45:05.000Z","dependencies_parsed_at":"2023-12-11T23:30:04.440Z","dependency_job_id":"df697640-b9dd-4616-a549-57230adaa0d1","html_url":"https://github.com/moka-rs/moka","commit_stats":{"total_commits":747,"total_committers":13,"mean_commits":57.46153846153846,"dds":"0.029451137884872858","last_synced_commit":"358a71ed1ed15b2353ff511d6004771a326edf15"},"previous_names":[],"tags_count":61,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moka-rs%2Fmoka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moka-rs%2Fmoka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moka-rs%2Fmoka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moka-rs%2Fmoka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moka-rs","download_url":"https://codeload.github.com/moka-rs/moka/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253514559,"owners_count":21920334,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","concurrent-data-structure"],"created_at":"2024-07-31T23:00:49.071Z","updated_at":"2026-01-26T02:17:39.169Z","avatar_url":"https://github.com/moka-rs.png","language":"Rust","funding_links":["https://github.com/sponsors/tatsuya6502"],"categories":["Libraries","Rust"],"sub_categories":["Caching"],"readme":"# Moka\n\n[![GitHub Actions][gh-actions-badge]][gh-actions]\n[![crates.io release][release-badge]][crate]\n[![docs][docs-badge]][docs]\n[![DeepWiki][deepwiki-badge]][deepwiki]\n[![dependency status][deps-rs-badge]][deps-rs]\n[![codecov][codecov-badge]][codecov]\n[![license][license-badge]](#license)\n\n\u003e [!NOTE]\n\u003e If you have any questions about Moka's APIs or internal design, ask the AI chatbot\n\u003e at DeepWiki in any natural language: \u003chttps://deepwiki.com/moka-rs/moka\u003e\n\n\u003e [!NOTE]\n\u003e `v0.12.0` had major breaking changes on the API and internal behavior. Please read\n\u003e the [MIGRATION-GUIDE.md][migration-guide-v012] for the details.\n\n* * *\n\nMoka is a fast, concurrent cache library for Rust. Moka is inspired by the\n[Caffeine][caffeine-git] library for Java.\n\nMoka provides cache implementations on top of hash maps. They support full\nconcurrency of retrievals and a high expected concurrency for updates.\n\nAll caches perform a best-effort bounding of a hash map using an entry replacement\nalgorithm to determine which entries to evict when the capacity is exceeded.\n\n[gh-actions-badge]: https://github.com/moka-rs/moka/workflows/CI/badge.svg\n[release-badge]: https://img.shields.io/crates/v/moka.svg\n[docs-badge]: https://docs.rs/moka/badge.svg\n[deepwiki-badge]: https://deepwiki.com/badge.svg\n[deps-rs-badge]: https://deps.rs/repo/github/moka-rs/moka/status.svg\n[codecov-badge]: https://codecov.io/gh/moka-rs/moka/graph/badge.svg?token=7GYZNS7O67\n[license-badge]: https://img.shields.io/crates/l/moka.svg\n\n[gh-actions]: https://github.com/moka-rs/moka/actions?query=workflow%3ACI\n[crate]: https://crates.io/crates/moka\n[docs]: https://docs.rs/moka\n[deepwiki]: https://deepwiki.com/moka-rs/moka\n[deps-rs]: https://deps.rs/repo/github/moka-rs/moka\n[codecov]: https://codecov.io/gh/moka-rs/moka\n\n[caffeine-git]: https://github.com/ben-manes/caffeine\n\n\n## Features\n\nMoka provides a rich and flexible feature set while maintaining high hit ratio and a\nhigh level of concurrency for concurrent access.\n\n- Thread-safe, highly concurrent in-memory cache implementations:\n    - Synchronous caches that can be shared across OS threads.\n    - An asynchronous (futures aware) cache.\n- A cache can be bounded by one of the followings:\n    - The maximum number of entries.\n    - The total weighted size of entries. (Size aware eviction)\n- Maintains near optimal hit ratio by using an entry replacement algorithms inspired\n  by Caffeine:\n    - Admission to a cache is controlled by the Least Frequently Used (LFU) policy.\n    - Eviction from a cache is controlled by the Least Recently Used (LRU) policy.\n    - [More details and some benchmark results are available here][tiny-lfu].\n- Supports expiration policies:\n    - Time to live.\n    - Time to idle.\n    - Per-entry variable expiration.\n- Supports eviction listener, a callback function that will be called when an entry\n  is removed from the cache.\n\n### Choosing the right cache for your use case\n\nNo cache implementation is perfect for every use cases. Moka is a complex software\nand can be overkill for your use case. Sometimes simpler caches like\n[Mini Moka][mini-moka-crate] or [Quick Cache][quick-cache] might be a better fit.\n\nThe following table shows the trade-offs between the different cache implementations:\n\n| Feature | Moka v0.12 | Mini Moka v0.10 | Quick Cache v0.6 |\n|:------- |:---- |:--------- |:----------- |\n| Thread-safe, sync cache | ✅ | ✅ | ✅ |\n| Thread-safe, async cache | ✅ | ❌ | ✅ |\n| Non-concurrent cache | ❌ | ✅ | ✅ |\n| Bounded by the maximum number of entries | ✅ | ✅ | ✅ |\n| Bounded by the total weighted size of entries | ✅ | ✅ | ✅ |\n| Near optimal hit ratio | ✅ TinyLFU | ✅ TinyLFU | ✅ S3-FIFO |\n| Per-key, atomic insertion. (e.g. `get_with` method) | ✅ | ❌ | ✅ |\n| Cache-level expiration policies (time-to-live and time-to-idle) | ✅ | ✅ | ❌ |\n| Per-entry variable expiration | ✅ | ❌ | ❌ |\n| Eviction listener | ✅ | ❌ | ✅ (via lifecycle hook) |\n| Lock-free, concurrent iterator | ✅ | ❌ | ❌ |\n| Lock-per-shard, concurrent iterator | ❌ | ✅ | ❌ |\n\n| Performance, etc. | Moka v0.12 | Mini Moka v0.10 | Quick Cache v0.6 |\n|:------- |:---- |:--------- |:----------- |\n| Small overhead compared to a concurrent hash table | ❌ | ❌ | ✅ |\n| Does not use background threads | ❌ → ✅ Removed from v0.12 | ✅ | ✅ |\n| Small dependency tree | ❌ | ✅ | ✅ |\n\n[tiny-lfu]: https://github.com/moka-rs/moka/wiki#admission-and-eviction-policies\n[quick-cache]: https://crates.io/crates/quick_cache\n[mini-moka-crate]: https://crates.io/crates/mini-moka\n\n## Moka in Production\n\nMoka is powering production services as well as embedded Linux devices like home\nrouters. Here are some highlights:\n\n- [crates.io](https://crates.io/): The official crate registry has been using Moka in\n  its API service to reduce the loads on PostgreSQL. Moka is maintaining\n  [cache hit rates of ~85%][gh-discussions-51] for the high-traffic download endpoint.\n  (Moka used: Nov 2021 \u0026mdash; present)\n- [aliyundrive-webdav][aliyundrive-webdav-git]: This WebDAV gateway for a cloud drive\n  may have been deployed in hundreds of home Wi-Fi routers, including inexpensive\n  models with 32-bit MIPS or ARMv5TE-based SoCs. Moka is used to cache the metadata\n  of remote files. (Moka used: Aug 2021 \u0026mdash; present)\n\n[gh-discussions-51]: https://github.com/moka-rs/moka/discussions/51\n[aliyundrive-webdav-git]: https://github.com/messense/aliyundrive-webdav\n\n\n## Recent Changes\n\n\u003e [!NOTE]\n\u003e `v0.12.0` had major breaking changes on the API and internal behavior. Please read\n\u003e the [MIGRATION-GUIDE.md][migration-guide-v012] for the details.\n\n- [MIGRATION-GUIDE.md][migration-guide-v012]\n- [CHANGELOG.md](https://github.com/moka-rs/moka/blob/main/CHANGELOG.md)\n\n[migration-guide-v012]: https://github.com/moka-rs/moka/blob/main/MIGRATION-GUIDE.md\n\n\n## Table of Contents\n\n- [Features](#features)\n    - [Choosing the right cache for your use case](#choosing-the-right-cache-for-your-use-case)\n- [Moka in Production](#moka-in-production)\n- [Change Log](#change-log)\n- [Supported Platforms](#supported-platforms)\n- [Usage](#usage)\n- Examples (Part 1)\n    - [Synchronous Cache](#example-synchronous-cache)\n    - [Asynchronous Cache](#example-asynchronous-cache)\n- [Avoiding to clone the value at `get`](#avoiding-to-clone-the-value-at-get)\n- Example (Part 2)\n    - [Size Aware Eviction](#example-size-aware-eviction)\n- [Expiration Policies](#expiration-policies)\n- [Minimum Supported Rust Versions](#minimum-supported-rust-versions)\n- Troubleshooting\n    - [Compile Errors on Some 32-bit Platforms](#compile-errors-on-some-32-bit-platforms)\n- [Developing Moka](#developing-moka)\n- [Road Map](#road-map)\n- [About the Name](#about-the-name)\n- [Credits](#credits)\n- [License](#license)\n\n\n## Supported Platforms\n\nMoka should work on most 64-bit and 32-bit platforms if Rust `std` library is\navailable with threading support. However, WebAssembly (Wasm) and WASI targets are\nnot supported.\n\nThe following platforms are tested on CI:\n\n- Linux 64-bit (x86_64, arm aarch64)\n- Linux 32-bit (i646, armv7, armv5, mips)\n    - If you get compile errors on 32-bit platforms, see\n      [troubleshooting](#compile-errors-on-some-32-bit-platforms).\n\nThe following platforms are not tested on CI but should work:\n\n- macOS (arm64)\n- Windows (x86_64 msvc and gnu)\n- iOS (arm64)\n\nThe following platforms are _not_ supported:\n\n- WebAssembly (Wasm) and WASI targets are not supported.\n  (See [this project task][gh-proj-49877487])\n- `nostd` environment (platforms without `std` library) are not supported.\n- 16-bit platforms are not supported.\n\n[gh-proj-49877487]: https://github.com/orgs/moka-rs/projects/1?pane=issue\u0026itemId=49877487\n\n\n## Usage\n\nTo add Moka to your dependencies, run `cargo add` as the followings:\n\n```console\n# To use the synchronous cache:\ncargo add moka --features sync\n\n# To use the asynchronous cache:\ncargo add moka --features future\n```\n\nIf you want to use the cache under an async runtime such as `tokio` or `async-std`, you should specify the `future` feature. Otherwise, specify the `sync` feature.\n\n\n## Example: Synchronous Cache\n\nThe thread-safe, synchronous caches are defined in the `sync` module.\n\nCache entries are manually added using `insert` or `get_with` method, and\nare stored in the cache until either evicted or manually invalidated.\n\nHere's an example of reading and updating a cache by using multiple threads:\n\n```rust\n// Use the synchronous cache.\nuse moka::sync::Cache;\n\nuse std::thread;\n\nfn value(n: usize) -\u003e String {\n    format!(\"value {n}\")\n}\n\nfn main() {\n    const NUM_THREADS: usize = 16;\n    const NUM_KEYS_PER_THREAD: usize = 64;\n\n    // Create a cache that can store up to 10,000 entries.\n    let cache = Cache::new(10_000);\n\n    // Spawn threads and read and update the cache simultaneously.\n    let threads: Vec\u003c_\u003e = (0..NUM_THREADS)\n        .map(|i| {\n            // To share the same cache across the threads, clone it.\n            // This is a cheap operation.\n            let my_cache = cache.clone();\n            let start = i * NUM_KEYS_PER_THREAD;\n            let end = (i + 1) * NUM_KEYS_PER_THREAD;\n\n            thread::spawn(move || {\n                // Insert 64 entries. (NUM_KEYS_PER_THREAD = 64)\n                for key in start..end {\n                    my_cache.insert(key, value(key));\n                    // get() returns Option\u003cString\u003e, a clone of the stored value.\n                    assert_eq!(my_cache.get(\u0026key), Some(value(key)));\n                }\n\n                // Invalidate every 4 element of the inserted entries.\n                for key in (start..end).step_by(4) {\n                    my_cache.invalidate(\u0026key);\n                }\n            })\n        })\n        .collect();\n\n    // Wait for all threads to complete.\n    threads.into_iter().for_each(|t| t.join().expect(\"Failed\"));\n\n    // Verify the result.\n    for key in 0..(NUM_THREADS * NUM_KEYS_PER_THREAD) {\n        if key % 4 == 0 {\n            assert_eq!(cache.get(\u0026key), None);\n        } else {\n            assert_eq!(cache.get(\u0026key), Some(value(key)));\n        }\n    }\n}\n```\n\nYou can try the synchronous example by cloning the repository and running the\nfollowing cargo instruction:\n\n```console\n$ cargo run --example sync_example\n```\n\nIf you want to atomically initialize and insert a value when the key is not present,\nyou might want to check [the document][doc-sync-cache] for other insertion methods\n`get_with` and `try_get_with`.\n\n[doc-sync-cache]: https://docs.rs/moka/*/moka/sync/struct.Cache.html#method.get_with\n\n\n## Example: Asynchronous Cache\n\nThe asynchronous (futures aware) cache is defined in the `future` module.\nIt works with asynchronous runtime such as [Tokio][tokio-crate],\n[async-std][async-std-crate] or [actix-rt][actix-rt-crate].\nTo use the asynchronous cache, [enable a crate feature called \"future\"](#usage).\n\n[tokio-crate]: https://crates.io/crates/tokio\n[async-std-crate]: https://crates.io/crates/async-std\n[actix-rt-crate]: https://crates.io/crates/actix-rt\n\nCache entries are manually added using an insert method, and are stored in the cache\nuntil either evicted or manually invalidated:\n\n- Inside an async context (`async fn` or `async` block), use `insert` or `invalidate`\n  method for updating the cache and `await` them.\n- Outside any async context, use `blocking` method to access blocking version of\n  `insert` or `invalidate` methods.\n\nHere is a similar program to the previous example, but using asynchronous cache with\n[Tokio][tokio-crate] runtime:\n\n```rust,ignore\n// Cargo.toml\n//\n// [dependencies]\n// moka = { version = \"0.12\", features = [\"future\"] }\n// tokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\" ] }\n// futures-util = \"0.3\"\n\n// Use the asynchronous cache.\nuse moka::future::Cache;\n\n#[tokio::main]\nasync fn main() {\n    const NUM_TASKS: usize = 16;\n    const NUM_KEYS_PER_TASK: usize = 64;\n\n    fn value(n: usize) -\u003e String {\n        format!(\"value {n}\")\n    }\n\n    // Create a cache that can store up to 10,000 entries.\n    let cache = Cache::new(10_000);\n\n    // Spawn async tasks and write to and read from the cache.\n    let tasks: Vec\u003c_\u003e = (0..NUM_TASKS)\n        .map(|i| {\n            // To share the same cache across the async tasks, clone it.\n            // This is a cheap operation.\n            let my_cache = cache.clone();\n            let start = i * NUM_KEYS_PER_TASK;\n            let end = (i + 1) * NUM_KEYS_PER_TASK;\n\n            tokio::spawn(async move {\n                // Insert 64 entries. (NUM_KEYS_PER_TASK = 64)\n                for key in start..end {\n                    // insert() is an async method, so await it.\n                    my_cache.insert(key, value(key)).await;\n                    // get() returns Option\u003cString\u003e, a clone of the stored value.\n                    assert_eq!(my_cache.get(\u0026key).await, Some(value(key)));\n                }\n\n                // Invalidate every 4 element of the inserted entries.\n                for key in (start..end).step_by(4) {\n                    // invalidate() is an async method, so await it.\n                    my_cache.invalidate(\u0026key).await;\n                }\n            })\n        })\n        .collect();\n\n    // Wait for all tasks to complete.\n    futures_util::future::join_all(tasks).await;\n\n    // Verify the result.\n    for key in 0..(NUM_TASKS * NUM_KEYS_PER_TASK) {\n        if key % 4 == 0 {\n            assert_eq!(cache.get(\u0026key).await, None);\n        } else {\n            assert_eq!(cache.get(\u0026key).await, Some(value(key)));\n        }\n    }\n}\n```\n\nYou can try the asynchronous example by cloning the repository and running the\nfollowing cargo instruction:\n\n```console\n$ cargo run --example async_example --features future\n```\n\nIf you want to atomically initialize and insert a value when the key is not present,\nyou might want to check [the document][doc-future-cache] for other insertion methods\n`get_with` and `try_get_with`.\n\n[doc-future-cache]: https://docs.rs/moka/*/moka/future/struct.Cache.html#method.get_with\n\n\n## Avoiding to clone the value at `get`\n\nFor the concurrent caches (`sync` and `future` caches), the return type of `get`\nmethod is `Option\u003cV\u003e` instead of `Option\u003c\u0026V\u003e`, where `V` is the value type. Every\ntime `get` is called for an existing key, it creates a clone of the stored value `V`\nand returns it. This is because the `Cache` allows concurrent updates from threads so\na value stored in the cache can be dropped or replaced at any time by any other\nthread. `get` cannot return a reference `\u0026V` as it is impossible to guarantee the\nvalue outlives the reference.\n\nIf you want to store values that will be expensive to clone, wrap them by\n`std::sync::Arc` before storing in a cache. [`Arc`][rustdoc-std-arc] is a thread-safe\nreference-counted pointer and its `clone()` method is cheap.\n\n[rustdoc-std-arc]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html\n\n```rust,ignore\nuse std::sync::Arc;\n\nlet key = ...\nlet large_value = vec![0u8; 2 * 1024 * 1024]; // 2 MiB\n\n// When insert, wrap the large_value by Arc.\ncache.insert(key.clone(), Arc::new(large_value));\n\n// get() will call Arc::clone() on the stored value, which is cheap.\ncache.get(\u0026key);\n```\n\n\n## Example: Size Aware Eviction\n\nIf different cache entries have different \"weights\" \u0026mdash; e.g. each entry has\ndifferent memory footprints \u0026mdash; you can specify a `weigher` closure at the cache\ncreation time. The closure should return a weighted size (relative size) of an entry\nin `u32`, and the cache will evict entries when the total weighted size exceeds its\n`max_capacity`.\n\n```rust\nuse moka::sync::Cache;\n\nfn main() {\n    let cache = Cache::builder()\n        // A weigher closure takes \u0026K and \u0026V and returns a u32 representing the\n        // relative size of the entry. Here, we use the byte length of the value\n        // String as the size.\n        .weigher(|_key, value: \u0026String| -\u003e u32 {\n            value.len().try_into().unwrap_or(u32::MAX)\n        })\n        // This cache will hold up to 32MiB of values.\n        .max_capacity(32 * 1024 * 1024)\n        .build();\n    cache.insert(0, \"zero\".to_string());\n}\n```\n\nNote that weighted sizes are not used when making eviction selections.\n\nYou can try the size aware eviction example by cloning the repository and running the\nfollowing cargo instruction:\n\n```console\n$ cargo run --example size_aware_eviction\n```\n\n\n## Expiration Policies\n\nMoka supports the following expiration policies:\n\n- **Cache-level expiration policies:**\n    - Cache-level policies are applied to all entries in the cache.\n    - **Time to live (TTL)**: A cached entry will be expired after the specified\n      duration past from `insert`.\n    - **Time to idle (TTI)**: A cached entry will be expired after the specified\n      duration past from `get` or `insert`.\n- **Per-entry expiration policy:**\n    - The per-entry expiration lets you sets a different expiration time for each\n      entry.\n\nFor details and examples of above policies, see the \"Example: Time-based Expiration\"\nsection ([`sync::Cache`][doc-sync-cache-expiration],\n[`future::Cache`][doc-future-cache-expiration]) of the document.\n\n[doc-sync-cache-expiration]: https://docs.rs/moka/latest/moka/sync/struct.Cache.html#example-time-based-expirations\n[doc-future-cache-expiration]: https://docs.rs/moka/latest/moka/future/struct.Cache.html#example-time-based-expirations\n\n\n## Minimum Supported Rust Versions\n\nMoka's minimum supported Rust versions (MSRV) are the followings:\n\n| Feature  | MSRV                       |\n|:---------|:-----------------------------:|\n| `future` | Rust 1.71.1 (August 3, 2023) |\n| `sync`   | Rust 1.71.1 (August 3, 2023) |\n\nIt will keep a rolling MSRV policy of at least 6 months. If the default features with\na mandatory features (`future` or `sync`) are enabled, MSRV will be updated\nconservatively. When using other features, MSRV might be updated more frequently, up\nto the latest stable.\n\nIn both cases, increasing MSRV is _not_ considered a semver-breaking change.\n\n\u003c!--\n- quanta v0.12.4 requires 1.70.0.\n--\u003e\n\n## Troubleshooting\n\n### Compile Errors on Some 32-bit Platforms\n\n#### Symptoms\n\nWhen using Moka v0.12.9 or earlier on some 32-bit platforms, you may get compile\nerrors:\n\n```console\nerror[E0432]: unresolved import `std::sync::atomic::AtomicU64`\n  --\u003e ... /moka-0.5.3/src/sync.rs:10:30\n   |\n10 |         atomic::{AtomicBool, AtomicU64, Ordering},\n   |                              ^^^^^^^^^\n   |                              |\n   |                              no `AtomicU64` in `sync::atomic`\n```\n\nor\n\n```console\nerror[E0583]: file not found for module `atomic_time`\n  --\u003e ... /moka-0.12.9/src/common/concurrent.rs:23:1\n   |\n23 | pub(crate) mod atomic_time;\n   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n```\n\n#### How to Fix\n\nYou can fix these compilation errors by one of the following:\n\n1. (Recommended) Upgrade Moka to v0.12.10 or later. (`cargo update -p moka`)\n2. Or, keep using Moka v0.12.9 or earlier but disable the default features in\n   `Cargo.toml`. (`default-features = false`)\n    - The default features include the `atomic64` feature, which need to be disabled.\n\nThese error messages are caused by the absence of `std::sync::atomic::AtomicU64` on\nsome 32-bit platforms. Moka v0.12.10 and later will automatically use a fallback\nimplementation when `AtomicU64` is not available. With v0.12.9 and earlier, you must\nmanually disable the `atomic64` feature to use the fallback implementation.\n\n## Developing Moka\n\n**Running All Tests**\n\nTo run all tests including `future` feature and doc tests on the README, use the\nfollowing command:\n\n```console\n$ RUSTFLAGS='--cfg trybuild' cargo test --all-features\n```\n\n**Running All Tests without Default Features**\n\n```console\n$ RUSTFLAGS='--cfg trybuild' cargo test \\\n    --no-default-features --features 'future, sync'\n```\n\n**Generating the Doc**\n\n```console\n$ cargo +nightly -Z unstable-options --config 'build.rustdocflags=\"--cfg docsrs\"' \\\n    doc --no-deps --features 'future, sync'\n```\n\n## Roadmap\n\nSee the [project roadmap][gh-proj-1] for the updated and detailed plans.\n\nBut here are some highlights:\n\n[gh-proj-1]: https://github.com/orgs/moka-rs/projects/1/views/1\n\n- [x] Size-aware eviction. (`v0.7.0` via [#24][gh-pull-024])\n- [x] API stabilization. (Smaller core API, shorter names for frequently used\n       methods) (`v0.8.0` via [#105][gh-pull-105])\n    - e.g.\n    - `get_or_insert_with(K, F)` → `get_with(K, F)`\n    - `get_or_try_insert_with(K, F)` → `try_get_with(K, F)`\n    - `time_to_live()` → `policy().time_to_live()`\n- [x] Notifications on eviction. (`v0.9.0` via [#145][gh-pull-145])\n- [x] Variable (per-entry) expiration, using hierarchical timer wheels.\n  (`v0.11.0` via [#248][gh-pull-248])\n- [x] Remove background threads. (`v0.12.0` via [#294][gh-pull-294] and\n  [#316][gh-pull-316])\n- [x] Add upsert and compute methods. (`v0.12.3` via [#370][gh-pull-370])\n- [ ] Cache statistics (Hit rate, etc.). ([details][cache-stats])\n- [ ] Upgrade TinyLFU to Window-TinyLFU. ([details][tiny-lfu])\n- [ ] Restore cache from a snapshot. ([details][restore])\n\n[gh-pull-024]: https://github.com/moka-rs/moka/pull/24\n[gh-pull-105]: https://github.com/moka-rs/moka/pull/105\n[gh-pull-145]: https://github.com/moka-rs/moka/pull/145\n[gh-pull-248]: https://github.com/moka-rs/moka/pull/248\n[gh-pull-294]: https://github.com/moka-rs/moka/pull/294\n[gh-pull-316]: https://github.com/moka-rs/moka/pull/316\n[gh-pull-370]: https://github.com/moka-rs/moka/pull/370\n\n[cache-stats]: https://github.com/moka-rs/moka/issues/234\n[restore]: https://github.com/moka-rs/moka/issues/314\n\n## About the Name\n\nMoka is named after the [moka pot][moka-pot-wikipedia], a stove-top coffee maker that\nbrews espresso-like coffee using boiling water pressurized by steam.\n\nThis name would imply the following facts and hopes:\n\n- Moka is a part of the Java Caffeine cache family.\n- It is written in Rust. (Many moka pots are made of aluminum alloy or stainless\n  steel. We know they don't rust though)\n- It should be fast. (\"Espresso\" in Italian means express)\n- It should be easy to use, like a moka pot.\n\n[moka-pot-wikipedia]: https://en.wikipedia.org/wiki/Moka_pot\n\n\n## Credits\n\n### Caffeine\n\nMoka's architecture is heavily inspired by the [Caffeine][caffeine-git] library for\nJava. Thanks go to Ben Manes and all contributors of Caffeine.\n\n\n### cht\n\nThe source files of the concurrent hash table under `moka::cht` module were copied\nfrom the [cht crate v0.4.1][cht-v041] and modified by us. We did so for better\nintegration. cht v0.4.1 and earlier are licensed under the MIT license.\n\nThanks go to Gregory Meyer.\n\n[cht-v041]: https://github.com/Gregory-Meyer/cht/tree/v0.4.1\n\n\n## License\n\nMoka is distributed under either of\n\n- The MIT license\n- The Apache License 2.0\n\nat your option.\n\nSee [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE) for details.\n\n**Note on Licensing:**\n\nCertain components, specifically\n[`src/common/frequency_sketch.rs`](src/common/frequency_sketch.rs) and\n[`src/common/timer_wheel.rs`](src/common/timer_wheel.rs), are distributed solely\nunder the Apache License 2.0. These files were ported from the [Caffeine][caffeine-git]\nlibrary and are not dual-licensed.\n\n\u003c!--\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fmoka-rs%2Fmoka.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fmoka-rs%2Fmoka?ref=badge_large)\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoka-rs%2Fmoka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoka-rs%2Fmoka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoka-rs%2Fmoka/lists"}