{"id":19333429,"url":"https://github.com/zakarumych/tiny-fn","last_synced_at":"2025-04-23T00:30:40.073Z","repository":{"id":50695403,"uuid":"519873617","full_name":"zakarumych/tiny-fn","owner":"zakarumych","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-22T16:25:42.000Z","size":25,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-31T12:08:57.250Z","etag":null,"topics":["rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zakarumych.png","metadata":{"files":{"readme":"README.md","changelog":null,"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},"funding":null},"created_at":"2022-07-31T19:51:42.000Z","updated_at":"2024-10-14T00:18:08.000Z","dependencies_parsed_at":"2022-08-25T12:30:12.971Z","dependency_job_id":null,"html_url":"https://github.com/zakarumych/tiny-fn","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Ftiny-fn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Ftiny-fn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Ftiny-fn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Ftiny-fn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zakarumych","download_url":"https://codeload.github.com/zakarumych/tiny-fn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223906277,"owners_count":17223046,"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":["rust"],"created_at":"2024-11-10T02:52:23.463Z","updated_at":"2024-11-10T02:52:23.922Z","avatar_url":"https://github.com/zakarumych.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TinyFn crate\n\n[![crates](https://img.shields.io/crates/v/tiny-fn.svg?style=for-the-badge\u0026label=tiny-fn)](https://crates.io/crates/tiny-fn)\n[![docs](https://img.shields.io/badge/docs.rs-tiny--fn-66c2a5?style=for-the-badge\u0026labelColor=555555\u0026logoColor=white)](https://docs.rs/tiny-fn)\n[![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING)\n\n# Motivation\n\nHave you ever being placing closure into [`Box\u003cdyn Fn(...)\u003e`] and wondered:\n\"Is there a crate to avoid heap allocations for small closures?\"\n\nWonder no more, this is the crate.\n\n# How to use\n\nThis crate provides declarative macro [`tiny_fn!`] to generates closure wrappers\nable store closure erasing its type.\n\nGenerated closure wrappers avoid heap allocations when wrapped closure fits inline storage.\n\nThe macro is designed to be easy to write with simple syntax that mostly reuse constructs already existing in Rust.\\\nBehavior of generated wrappers should be obvious from the first glance.\n\n# Example\n\n```rust\ntiny_fn! {\n    struct Foo = Fn(a: i32, b: i32) -\u003e i32;\n}\n\nlet foo: Foo = Foo::new(|a, b| a + b);\nassert_eq!(foo.call(1, 2), 3);\n```\n\nMacro expands to `struct Foo` definition with two public methods.\n\n* `Foo::new` accepts any value that implements [`Fn(i32, i32) -\u003e i32`] and returns new instance of `Foo`.\n* `Foo::call` follows signature specified to the macro. e.g. `Foo::call` accepts `a: i32` and `b: i32` and returns [`i32`].\\\n  Plainly `Foo::call` calls closure from which this instance of `Foo` was crated using `a` and `b` arguments at the same positions.\n\n[`tiny_fn!`] macro supports defining multiple items at once.\n\n```rust\ntiny_fn! {\n    struct Foo = Fn(a: i32, b: i32) -\u003e i32;\n    struct Bar = Fn() -\u003e String;\n}\n\nlet foo: Foo = Foo::new(|a, b| a + b);\nlet bar: Bar = Bar::new(|| \"Hello, World!\".to_string());\n\nassert_eq!(foo.call(1, 2), 3);\nassert_eq!(bar.call(), \"Hello, World!\");\n```\n\n# Visibility\n\n[`tiny_fn!`] macro supports visibility qualifiers.\n\n```rust\ntiny_fn! {\n    pub struct Foo = Fn(a: i32, b: i32) -\u003e i32;\n    struct Bar = Fn() -\u003e String;\n    pub(crate) struct Baz = Fn();\n}\n```\n\n# Attributes\n\n[`tiny_fn!`] macro supports item attributes, including documentation.\n\n```rust\ntiny_fn! {\n    /// This is `Foo` wrapper for that takes two `i32`s and return `i32`.\n    pub struct Foo = Fn(a: i32, b: i32) -\u003e i32;\n}\n```\n\n# [`Fn*`] traits family\n\n[`tiny_fn!`] macro can generate closure wrappers for any of the [`Fn*`] traits family.\n\n```rust\ntiny_fn! {\n    struct A = Fn();\n    struct B = FnMut();\n    struct C = FnOnce();\n}\n\nlet a = 42;\nlet a: A = A::new(|| println!(\"{}\", a));\na.call();\na.call();\n\nlet mut b = 42;\nlet mut b: B = B::new(|| b += 1);\nb.call();\nb.call();\n\nlet c = String::from(\"Hello, World!\");\nlet c: C = C::new(move || println!(\"{}\", c));\nc.call();\n// c.call(); // This will not compile, because `C` can be called only once.\n```\n\n* `A` can wrap only closures that are callable when immutably borrowed. And so `A::call` takes `\u0026self`.\n* `B` can wrap only closures that are callable when borrowed. And so `B::call` takes `\u0026mut self`.\n* `C` can wrap any closures, even ones that are callable once. And so `C::call` takes `self`.\n\n# Generics\n\nClosure wrappers can be declared generic over number of types and those types should be used in function signature.\n\n```rust\ntiny_fn! {\n    struct BinOp\u003cT\u003e = Fn(a: T, b: T) -\u003e T;\n}\n\nlet add: BinOp\u003ci32\u003e = BinOp::new(|a, b| a + b);\nlet mul: BinOp\u003ci32\u003e = BinOp::new(|a, b| a * b);\n\nassert_eq!(mul.call(add.call(1, 2), 3), 9);\n```\n\nHere `BinOp` is generic over `T`.\\\n`BiOp::\u003cT\u003e::new` accepts closures bounds by [`Fn(T, T) -\u003e T`].\n\nNotably `T` is not constrained by traits in `BinOp`.\\\nClosure wrappers only move arguments and return values, so they don't need to know anything else about the type.\n\n# Markers\n\nClosure wrappers can be declared with marker traits.\nSimply add `|` and list of `+` prefixed marker traits after function signature.\nIn Fn traits family `|` symbol is not used, but here it is required due to declarative macro limitations.\n\nThey will be added to bounds on contained types.\nAnd if autotraits, they will be implemented for the wrapper type as well.\n\n```rust\ntiny_fn! {\n    struct Foo = Fn(a: i32, b: i32) -\u003e i32 | + Send;\n}\n\nlet foo: Foo = Foo::new(|a, b| a + b);\n\nstd::thread::spawn(move || {\n  foo.call(1, 2);\n});\n```\n\n# Special generic parameters\n\nClosure wrapper generated by [`tiny_fn!`] macro always have two generic parameters besides generic types specified by macro caller:\n* Lifetime `'closure`.\\\n  Wrapper contains closures bound by `'closure` lifetime.\n* Constant `INLINE_SIZE: usize`.\\\n  Closures with size up to `INLINE_SIZE` and alignment requirement not exceeding [`tiny_fn::ALIGN`] will be inlined into wrapper structure directly.\\\n  Otherwise heap allocation will occur.\\\n  `INLINE_SIZE` parameter is defaulted to [`tiny_fn::DEFAULT_INLINE_SIZE`].\n\n[`Box\u003cdyn Fn(...)\u003e`]: https://doc.rust-lang.org/std/boxed/struct.Box.html\n[`i32`]: https://doc.rust-lang.org/std/primitive.i32.html\n[`tiny_fn!`]: https://docs.rs/tiny-fn/latest/tiny_fn/macro.tiny_fn.html\n[`Fn(i32, i32) -\u003e i32`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n[`Fn(T, T) -\u003e T`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n[`tiny_fn::ALIGN`]: https://docs.rs/tiny-fn/latest/tiny_fn/constant.ALIGN.html\n[`tiny_fn::DEFAULT_INLINE_SIZE`]: https://docs.rs/tiny-fn/latest/tiny_fn/constant.DEFAULT_INLINE_SIZE.html\n\n## License\n\nLicensed under either of\n\n* Apache License, Version 2.0, ([license/APACHE](license/APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n* MIT license ([license/MIT](license/MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n## Contributions\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzakarumych%2Ftiny-fn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzakarumych%2Ftiny-fn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzakarumych%2Ftiny-fn/lists"}