{"id":15626351,"url":"https://github.com/kobzol/rust-delegate","last_synced_at":"2025-05-14T03:07:08.741Z","repository":{"id":37678138,"uuid":"133896303","full_name":"Kobzol/rust-delegate","owner":"Kobzol","description":"Rust method delegation with less boilerplate","archived":false,"fork":false,"pushed_at":"2024-10-09T21:43:13.000Z","size":121,"stargazers_count":445,"open_issues_count":2,"forks_count":18,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-10-29T15:12:54.526Z","etag":null,"topics":["delegation","rust","rust-library","rust-macro"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/delegate","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/Kobzol.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2018-05-18T03:09:12.000Z","updated_at":"2024-10-24T23:30:32.000Z","dependencies_parsed_at":"2023-12-14T17:48:09.477Z","dependency_job_id":"67dc8036-d976-4379-92ac-76c051318fe2","html_url":"https://github.com/Kobzol/rust-delegate","commit_stats":{"total_commits":114,"total_committers":15,"mean_commits":7.6,"dds":"0.39473684210526316","last_synced_commit":"aecddaed3b4624866a41fa4291bcbaa8ffbebca3"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Frust-delegate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Frust-delegate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Frust-delegate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Frust-delegate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kobzol","download_url":"https://codeload.github.com/Kobzol/rust-delegate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248288357,"owners_count":21078903,"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":["delegation","rust","rust-library","rust-macro"],"created_at":"2024-10-03T10:12:02.745Z","updated_at":"2025-04-10T20:11:18.015Z","avatar_url":"https://github.com/Kobzol.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Method delegation with less boilerplate\n\n[![Build Status](https://github.com/kobzol/rust-delegate/workflows/Tests/badge.svg)](https://github.com/kobzol/rust-delegate/actions)\n[![Crates.io](https://img.shields.io/crates/v/delegate.svg)](https://crates.io/crates/delegate)\n\nThis crate removes some boilerplate for structs that simply delegate some of\ntheir methods to one or more of their fields.\n\nIt gives you the `delegate!` macro, which delegates method calls to selected\nexpressions (usually inner fields).\n\n## Example:\n\nA Stack data structure implemented using an inner Vec via delegation.\n\n```rust\nuse delegate::delegate;\n\n#[derive(Clone, Debug)]\nstruct Stack\u003cT\u003e {\n    inner: Vec\u003cT\u003e,\n}\nimpl\u003cT\u003e Stack\u003cT\u003e {\n    pub fn new() -\u003e Self \u003cT\u003e {\n        Self { inner: vec![] }\n    }\n\n    delegate! {\n        to self.inner {\n            pub fn is_empty(\u0026self) -\u003e bool;\n            pub fn push(\u0026mut self, value: T);\n            pub fn pop(\u0026mut self) -\u003e Option\u003cT\u003e;\n            pub fn clear(\u0026mut self);\n\n            #[call(len)]\n            pub fn size(\u0026self) -\u003e usize;\n\n            #[call(last)]\n            pub fn peek(\u0026self) -\u003e Option\u003c\u0026T\u003e;\n\n        }\n    }\n}\n```\n\n## Features\n\n### Delegate to a method with a different name\n```rust\nstruct Stack {\n    inner: Vec\u003cu32\u003e\n}\nimpl Stack {\n    delegate! {\n        to self.inner {\n            #[call(push)]\n            pub fn add(\u0026mut self, value: u32);\n        }\n    }\n}\n```\n\n### Use an arbitrary inner field expression\n```rust\nstruct Wrapper {\n    inner: Rc\u003cRefCell\u003cVec\u003cu32\u003e\u003e\u003e\n}\nimpl Wrapper {\n    delegate! {\n        to self.inner.deref().borrow_mut() {\n            pub fn push(\u0026mut self, val: u32);\n        }\n    }\n}\n```\n\n### Delegate to enum variants\n```rust\nuse delegate::delegate;\n\nenum Enum {\n    A(A),\n    B(B),\n    C { v: C },\n}\n\nstruct A {\n    val: usize,\n}\n\nimpl A {\n    fn dbg_inner(\u0026self) -\u003e usize {\n        dbg!(self.val);\n        1\n    }\n}\nstruct B {\n    val_a: String,\n}\n\nimpl B {\n    fn dbg_inner(\u0026self) -\u003e usize {\n        dbg!(self.val_a.clone());\n        2\n    }\n}\n\nstruct C {\n    val_c: f64,\n}\n\nimpl C {\n    fn dbg_inner(\u0026self) -\u003e usize {\n        dbg!(self.val_c);\n        3\n    }\n}\n\nimpl Enum {\n    delegate! {\n        // transformed to\n        //\n        // ```rust\n        // match self {\n        //     Enum::A(a) =\u003e a.dbg_inner(),\n        //     Enum::B(b) =\u003e { println!(\"i am b\"); b }.dbg_inner(),\n        //     Enum::C { v: c } =\u003e { c }.dbg_inner(),\n        // }\n        // ```\n        to match self {\n            Enum::A(a) =\u003e a,\n            Enum::B(b) =\u003e { println!(\"i am b\"); b },\n            Enum::C { v: c } =\u003e { c },\n        } {\n            fn dbg_inner(\u0026self) -\u003e usize;\n        }\n    }\n}\n```\n\n### Use modifiers that alter the generated method body\n```rust\nuse delegate::delegate;\nstruct Inner;\nimpl Inner {\n    pub fn method(\u0026self, num: u32) -\u003e u32 { num }\n    pub fn method_res(\u0026self, num: u32) -\u003e Result\u003cu32, ()\u003e { Ok(num) }\n}\nstruct Wrapper {\n    inner: Inner\n}\nimpl Wrapper {\n    delegate! {\n        to self.inner {\n            // calls method, converts result to u64 using `From`\n            #[into]\n            pub fn method(\u0026self, num: u32) -\u003e u64;\n\n            // calls method, returns ()\n            #[call(method)]\n            pub fn method_noreturn(\u0026self, num: u32);\n\n            // calls method, converts result to i6 using `TryFrom`\n            #[try_into]\n            #[call(method)]\n            pub fn method2(\u0026self, num: u32) -\u003e Result\u003cu16, std::num::TryFromIntError\u003e;\n\n            // calls method_res, unwraps the result\n            #[unwrap]\n            pub fn method_res(\u0026self, num: u32) -\u003e u32;\n\n            // calls method_res, unwraps the result, then calls into\n            #[unwrap]\n            #[into]\n            #[call(method_res)]\n            pub fn method_res_into(\u0026self, num: u32) -\u003e u64;\n\n            // specify explicit type for into\n            #[into(u64)]\n            #[call(method)]\n            pub fn method_into_explicit(\u0026self, num: u32) -\u003e u64;\n        }\n    }\n}\n```\n\n### Custom called expression\n\nThe `#[expr()]` attribute can be used to modify the delegated call. You can use the `$` sigil as a placeholder for what delegate would normally expand to, and wrap that expression with custom code.\n\n_Note:_ the `$` placeholder isn't required and can be present multiple times if you want.\n\n```rust\nstruct A(Vec\u003cu8\u003e);\n\nimpl A {\n    delegate! {\n        to self.0 {\n            #[expr(*$.unwrap())]\n            /// Here `$` == `self.0.get(idx)`\n            /// Will expand to `*self.0.get(idx).unwrap()`\n            fn get(\u0026self, idx: usize) -\u003e u8;\n\n            #[call(get)]\n            #[expr($?.checked_pow(2))]\n            /// Here `$` == `self.0.get(idx)`\n            /// Will expand to `self.0.get(idx)?.checked_pow(2)`\n            fn get_checked_pow_2(\u0026self, idx: usize) -\u003e Option\u003cu8\u003e;\n        }\n    }\n}\n```\n\n### Add additional arguments to method\n```rust\nstruct Inner(u32);\nimpl Inner {\n    pub fn new(m: u32) -\u003e Self {\n        // some \"very complex\" constructing work\n        Self(m)\n    }\n    pub fn method(\u0026self, n: u32) -\u003e u32 {\n        self.0 + n\n    }\n}\n\nstruct Wrapper {\n    inner: OnceCell\u003cInner\u003e,\n}\n\nimpl Wrapper {\n    pub fn new() -\u003e Self {\n        Self {\n            inner: OnceCell::new(),\n        }\n    }\n    fn content(\u0026self, val: u32) -\u003e \u0026Inner {\n        self.inner.get_or_init(|| Inner(val))\n    }\n    delegate! {\n        to |k: u32| self.content(k) {\n            // `wrapper.method(k, num)` will call `self.content(k).method(num)`\n            pub fn method(\u0026self, num: u32) -\u003e u32;\n        }\n    }\n}\n```\n\n### Call `await` on async functions\n```rust\nstruct Inner;\nimpl Inner {\n    pub async fn method(\u0026self, num: u32) -\u003e u32 { num }\n}\nstruct Wrapper {\n    inner: Inner\n}\nimpl Wrapper {\n    delegate! {\n        to self.inner {\n            // calls method(num).await, returns impl Future\u003cOutput = u32\u003e\n            pub async fn method(\u0026self, num: u32) -\u003e u32;\n            // calls method(num).await.into(), returns impl Future\u003cOutput = u64\u003e\n            #[into]\n            #[call(method)]\n            pub async fn method_into(\u0026self, num: u32) -\u003e u64;\n        }\n    }\n}\n```\n\nYou can use the `#[await(true/false)]` attribute on delegated methods to specify\nif `.await` should be generated after the delegated expression. It will be\ngenerated by default if the delegated method is `async`.\n\n### Delegate to multiple fields\n```rust\nstruct MultiStack {\n    left: Vec\u003cu32\u003e,\n    right: Vec\u003cu32\u003e,\n}\nimpl MultiStack {\n    delegate! {\n        to self.left {\n            /// Push an item to the top of the left stack\n            #[call(push)]\n            pub fn push_left(\u0026mut self, value: u32);\n        }\n        to self.right {\n            /// Push an item to the top of the right stack\n            #[call(push)]\n            pub fn push_right(\u0026mut self, value: u32);\n        }\n    }\n}\n```\n\n### Inline attributes\n`rust-delegate` inserts `#[inline(always)]` automatically. You can override that decision by specifying `#[inline]`\nmanually on the delegated method.\n\n### Segment attributes\nYou can use an attribute on a whole delegation segment to automatically apply it to all methods in that segment:\n\n```rust\nstruct Wrapper {\n    inner: Inner\n}\n\nimpl Wrapper {\n    delegate! {\n   #[unwrap]\n   to self.inner {\n     fn foo(\u0026self) -\u003e u32; // calls self.inner.foo().unwrap()\n     fn bar(\u0026self) -\u003e u32; // calls self.inner.bar().unwrap()\n   }\n }\n}\n```\n\n### Adding additional arguments\nYou can specify expressions in the signature that will be used as delegated arguments:\n\n```rust\nuse delegate::delegate;\n\nstruct Inner;\nimpl Inner {\n    pub fn polynomial(\u0026self, a: i32, x: i32, b: i32, y: i32, c: i32) -\u003e i32 {\n        a + x * x + b * y + c\n    }\n}\nstruct Wrapper {\n    inner: Inner,\n    a: i32,\n    b: i32,\n    c: i32\n}\nimpl Wrapper {\n    delegate! {\n        to self.inner {\n            // Calls `polynomial` on `inner` with `self.a`, `self.b` and\n            // `self.c` passed as arguments `a`, `b`, and `c`, effectively\n            // calling `polynomial(self.a, x, self.b, y, self.c)`.\n            pub fn polynomial(\u0026self, [ self.a ], x: i32, [ self.b ], y: i32, [ self.c ]) -\u003e i32 ;\n            // Calls `polynomial` on `inner` with `0`s passed for arguments\n            // `a` and `x`, and `self.b` and `self.c` for `b` and `c`,\n            // effectively calling `polynomial(0, 0, self.b, y, self.c)`.\n            #[call(polynomial)]\n            pub fn linear(\u0026self, [ 0 ], [ 0 ], [ self.b ], y: i32, [ self.c ]) -\u003e i32 ;\n        }\n    }\n}\n```\n\n### Parameter modifiers\nYou can modify how will an input parameter be passed to the delegated method with parameter attribute modifiers. Currently, the following modifiers are supported:\n- `#[into]`: Calls `.into()` on the parameter passed to the delegated method.\n- `#[as_ref]`: Calls `.as_ref()` on the parameter passed to the delegated method.\n- `#[newtype]`: Accesses the first tuple element (`.0`) of the parameter passed to the delegated method.\n\n\u003e Note that these modifiers might be removed in the future, try to use the more general `#[expr]` mechanism to achieve this functionality.\n\n```rust\nuse delegate::delegate;\n\nstruct InnerType {}\nimpl InnerType {\n    fn foo(\u0026self, other: Self) {}\n}\n\nimpl From\u003cWrapper\u003e for InnerType {\n    fn from(wrapper: Wrapper) -\u003e Self {\n        wrapper.0\n    }\n}\n\nstruct Wrapper(InnerType);\nimpl Wrapper {\n    delegate! {\n        to self.0 {\n            // Calls `self.0.foo(other.into());`\n            pub fn foo(\u0026self, #[into] other: Self);\n            // Calls `self.0.bar(other.0);`\n            pub fn bar(\u0026self, #[newtype] other: Self);\n        }\n    }\n}\n```\n\n### Delegate associated functions\n```rust\nuse delegate::delegate;\n\nstruct A {}\nimpl A {\n    fn foo(a: u32) -\u003e u32 {\n        a + 1\n    }\n}\n\nstruct B;\n\nimpl B {\n    delegate! {\n        to A {\n            fn foo(a: u32) -\u003e u32;\n        }\n    }\n}\n\nassert_eq!(B::foo(1), 2);\n```\n\n### Delegate associated constants\n```rust\nuse delegate::delegate;\n\ntrait WithConst {\n    const TOTO: u8;\n}\n\nstruct A;\nimpl WithConst for A {\n    const TOTO: u8 = 1;\n}\n\nstruct B;\nimpl WithConst for B {\n    const TOTO: u8 = 2;\n}\nstruct C;\nimpl WithConst for C {\n    const TOTO: u8 = 2;\n}\n\nenum Enum {\n    A(A),\n    B(B),\n    C(C),\n}\n\nimpl Enum {\n    delegate! {\n        to match self {\n            Self::A(a) =\u003e a,\n            Self::B(b) =\u003e b,\n            Self::C(c) =\u003e { println!(\"hello from c\"); c },\n        } {\n            #[const(WithConst::TOTO)]\n            fn get_toto(\u0026self) -\u003e u8;\n        }\n    }\n}\n\nassert_eq!(Enum::A(A).get_toto(), \u003cA as WithConst\u003e::TOTO);\n```\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or\n  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## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n\n## Conduct\n\nPlease follow the [Rust Code of Conduct]. For escalation or moderation issues\nplease contact the crate author(s) listed in [`Cargo.toml`](./Cargo.toml).\n\n[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkobzol%2Frust-delegate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkobzol%2Frust-delegate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkobzol%2Frust-delegate/lists"}