{"id":13438493,"url":"https://github.com/jaemk/cached","last_synced_at":"2025-05-16T08:00:22.507Z","repository":{"id":37451221,"uuid":"86962621","full_name":"jaemk/cached","owner":"jaemk","description":"Rust cache structures and easy function memoization","archived":false,"fork":false,"pushed_at":"2025-03-03T03:56:19.000Z","size":617,"stargazers_count":1769,"open_issues_count":67,"forks_count":100,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-09T07:21:28.420Z","etag":null,"topics":["cache","caching","lrucache","memoization","rust","rust-caching","rustlang"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaemk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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}},"created_at":"2017-04-02T04:23:22.000Z","updated_at":"2025-05-08T16:58:47.000Z","dependencies_parsed_at":"2023-02-02T20:20:13.006Z","dependency_job_id":"db4fe09d-a072-4608-9221-2ea424b5441c","html_url":"https://github.com/jaemk/cached","commit_stats":{"total_commits":298,"total_committers":35,"mean_commits":8.514285714285714,"dds":0.5906040268456376,"last_synced_commit":"920e22bf44eb90acb87cb0cbccd1b0ca3a3f024e"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaemk%2Fcached","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaemk%2Fcached/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaemk%2Fcached/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaemk%2Fcached/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaemk","download_url":"https://codeload.github.com/jaemk/cached/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254493382,"owners_count":22080126,"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","caching","lrucache","memoization","rust","rust-caching","rustlang"],"created_at":"2024-07-31T03:01:06.008Z","updated_at":"2025-05-16T08:00:22.480Z","avatar_url":"https://github.com/jaemk.png","language":"Rust","funding_links":[],"categories":["Libraries","Rust","库 Libraries","库"],"sub_categories":["Caching","缓存 Caching","高速缓存"],"readme":"# cached\n\n[![Build Status](https://github.com/jaemk/cached/actions/workflows/build.yml/badge.svg)](https://github.com/jaemk/cached/actions/workflows/build.yml)\n[![crates.io](https://img.shields.io/crates/v/cached.svg)](https://crates.io/crates/cached)\n[![docs](https://docs.rs/cached/badge.svg)](https://docs.rs/cached)\n\n\u003e Caching structures and simplified function memoization\n\n`cached` provides implementations of several caching structures as well as a handy macros\nfor defining memoized functions.\n\nMemoized functions defined using [`#[cached]`](proc_macro::cached)/[`#[once]`](proc_macro::once)/[`#[io_cached]`](proc_macro::io_cached)/[`cached!`](crate::macros) macros are thread-safe with the backing\nfunction-cache wrapped in a mutex/rwlock, or externally synchronized in the case of `#[io_cached]`.\nBy default, the function-cache is **not** locked for the duration of the function's execution, so initial (on an empty cache)\nconcurrent calls of long-running functions with the same arguments will each execute fully and each overwrite\nthe memoized value as they complete. This mirrors the behavior of Python's `functools.lru_cache`. To synchronize the execution and caching\nof un-cached arguments, specify `#[cached(sync_writes = \"default\")]` / `#[once(sync_writes = true)]` (not supported by `#[io_cached]`.\n\n- See [`cached::stores` docs](https://docs.rs/cached/latest/cached/stores/index.html) cache stores available.\n- See [`proc_macro`](https://docs.rs/cached/latest/cached/proc_macro/index.html) for more procedural macro examples.\n- See [`macros`](https://docs.rs/cached/latest/cached/macros/index.html) for more declarative macro examples.\n\n**Features**\n\n- `default`: Include `proc_macro` and `ahash` features\n- `proc_macro`: Include proc macros\n- `ahash`: Enable the optional `ahash` hasher as default hashing algorithm.\n- `async`: Include support for async functions and async cache stores\n- `async_tokio_rt_multi_thread`: Enable `tokio`'s optional `rt-multi-thread` feature.\n- `redis_store`: Include Redis cache store\n- `redis_async_std`: Include async Redis support using `async-std` and `async-std` tls support, implies `redis_store` and `async`\n- `redis_tokio`: Include async Redis support using `tokio` and `tokio` tls support, implies `redis_store` and `async`\n- `redis_connection_manager`: Enable the optional `connection-manager` feature of `redis`. Any async redis caches created\n                              will use a connection manager instead of a `MultiplexedConnection`\n- `redis_ahash`: Enable the optional `ahash` feature of `redis`\n- `disk_store`: Include disk cache store\n- `wasm`: Enable WASM support. Note that this feature is incompatible with `tokio`'s multi-thread\n   runtime (`async_tokio_rt_multi_thread`) and all Redis features (`redis_store`, `redis_async_std`, `redis_tokio`, `redis_ahash`)\n\nThe procedural macros (`#[cached]`, `#[once]`, `#[io_cached]`) offer more features, including async support.\nSee the [`proc_macro`](crate::proc_macro) and [`macros`](crate::macros) modules for more samples, and the\n[`examples`](https://github.com/jaemk/cached/tree/master/examples) directory for runnable snippets.\n\nAny custom cache that implements `cached::Cached`/`cached::CachedAsync` can be used with the `#[cached]`/`#[once]`/`cached!` macros in place of the built-ins.\nAny custom cache that implements `cached::IOCached`/`cached::IOCachedAsync` can be used with the `#[io_cached]` macro.\n\n----\n\nThe basic usage looks like:\n\n```rust\nuse cached::proc_macro::cached;\n\n/// Defines a function named `fib` that uses a cache implicitly named `FIB`.\n/// By default, the cache will be the function's name in all caps.\n/// The following line is equivalent to #[cached(name = \"FIB\", unbound)]\n#[cached]\nfn fib(n: u64) -\u003e u64 {\n    if n == 0 || n == 1 { return n }\n    fib(n-1) + fib(n-2)\n}\n```\n\n----\n\n```rust\nuse std::thread::sleep;\nuse std::time::Duration;\nuse cached::proc_macro::cached;\nuse cached::SizedCache;\n\n/// Use an explicit cache-type with a custom creation block and custom cache-key generating block\n#[cached(\n    ty = \"SizedCache\u003cString, usize\u003e\",\n    create = \"{ SizedCache::with_size(100) }\",\n    convert = r#\"{ format!(\"{}{}\", a, b) }\"#\n)]\nfn keyed(a: \u0026str, b: \u0026str) -\u003e usize {\n    let size = a.len() + b.len();\n    sleep(Duration::new(size as u64, 0));\n    size\n}\n```\n\n----\n\n```rust\nuse cached::proc_macro::once;\n\n/// Only cache the initial function call.\n/// Function will be re-executed after the cache\n/// expires (according to `time` seconds).\n/// When no (or expired) cache, concurrent calls\n/// will synchronize (`sync_writes`) so the function\n/// is only executed once.\n#[once(time=10, option = true, sync_writes = true)]\nfn keyed(a: String) -\u003e Option\u003cusize\u003e {\n    if a == \"a\" {\n        Some(a.len())\n    } else {\n        None\n    }\n}\n```\n\n----\n\n```compile_fail\nuse cached::proc_macro::cached;\n\n/// Cannot use sync_writes and result_fallback together\n#[cached(\n    result = true,\n    time = 1,\n    sync_writes = \"default\",\n    result_fallback = true\n)]\nfn doesnt_compile() -\u003e Result\u003cString, ()\u003e {\n    Ok(\"a\".to_string())\n}\n```\n----\n\n```rust,no_run,ignore\nuse cached::proc_macro::io_cached;\nuse cached::AsyncRedisCache;\nuse thiserror::Error;\n\n#[derive(Error, Debug, PartialEq, Clone)]\nenum ExampleError {\n    #[error(\"error with redis cache `{0}`\")]\n    RedisError(String),\n}\n\n/// Cache the results of an async function in redis. Cache\n/// keys will be prefixed with `cache_redis_prefix`.\n/// A `map_error` closure must be specified to convert any\n/// redis cache errors into the same type of error returned\n/// by your function. All `io_cached` functions must return `Result`s.\n#[io_cached(\n    map_error = r##\"|e| ExampleError::RedisError(format!(\"{:?}\", e))\"##,\n    ty = \"AsyncRedisCache\u003cu64, String\u003e\",\n    create = r##\" {\n        AsyncRedisCache::new(\"cached_redis_prefix\", 1)\n            .set_refresh(true)\n            .build()\n            .await\n            .expect(\"error building example redis cache\")\n    } \"##\n)]\nasync fn async_cached_sleep_secs(secs: u64) -\u003e Result\u003cString, ExampleError\u003e {\n    std::thread::sleep(std::time::Duration::from_secs(secs));\n    Ok(secs.to_string())\n}\n```\n\n----\n\n```rust,no_run,ignore\nuse cached::proc_macro::io_cached;\nuse cached::DiskCache;\nuse thiserror::Error;\n\n#[derive(Error, Debug, PartialEq, Clone)]\nenum ExampleError {\n    #[error(\"error with disk cache `{0}`\")]\n    DiskError(String),\n}\n\n/// Cache the results of a function on disk.\n/// Cache files will be stored under the system cache dir\n/// unless otherwise specified with `disk_dir` or the `create` argument.\n/// A `map_error` closure must be specified to convert any\n/// disk cache errors into the same type of error returned\n/// by your function. All `io_cached` functions must return `Result`s.\n#[io_cached(\n    map_error = r##\"|e| ExampleError::DiskError(format!(\"{:?}\", e))\"##,\n    disk = true\n)]\nfn cached_sleep_secs(secs: u64) -\u003e Result\u003cString, ExampleError\u003e {\n    std::thread::sleep(std::time::Duration::from_secs(secs));\n    Ok(secs.to_string())\n}\n```\n\n\nFunctions defined via macros will have their results cached using the\nfunction's arguments as a key, a `convert` expression specified on a procedural macros,\nor a `Key` block specified on a `cached_key!` declarative macro.\n\nWhen a macro-defined function is called, the function's cache is first checked for an already\ncomputed (and still valid) value before evaluating the function body.\n\nDue to the requirements of storing arguments and return values in a global cache:\n\n- Function return types:\n  - For all store types, except Redis, must be owned and implement `Clone`\n  - For the Redis store type, must be owned and implement `serde::Serialize + serde::DeserializeOwned`\n- Function arguments:\n  - For all store types, except Redis, must either be owned and implement `Hash + Eq + Clone`,\n    the `cached_key!` macro is used with a `Key` block specifying key construction, or\n    a `convert` expression is specified on a procedural macro to specify how to construct a key\n    of a `Hash + Eq + Clone` type.\n  - For the Redis store type, must either be owned and implement `Display`, or the `cached_key!` \u0026 `Key`\n    or procedural macro \u0026 `convert` expression used to specify how to construct a key of a `Display` type.\n- Arguments and return values will be `cloned` in the process of insertion and retrieval. Except for Redis\n  where arguments are formatted into `Strings` and values are de/serialized.\n- Macro-defined functions should not be used to produce side-effectual results!\n- Macro-defined functions cannot live directly under `impl` blocks since macros expand to a\n  `once_cell` initialization and one or more function definitions.\n- Macro-defined functions cannot accept `Self` types as a parameter.\n\n\n\nLicense: MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaemk%2Fcached","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaemk%2Fcached","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaemk%2Fcached/lists"}