{"id":23978617,"url":"https://github.com/simmsb/enum_dispatch_async","last_synced_at":"2026-06-08T20:32:18.137Z","repository":{"id":94007314,"uuid":"581267298","full_name":"simmsb/enum_dispatch_async","owner":"simmsb","description":null,"archived":false,"fork":false,"pushed_at":"2022-12-22T18:19:15.000Z","size":141,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-22T00:03:15.742Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/simmsb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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":"2022-12-22T18:04:38.000Z","updated_at":"2022-12-22T18:04:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"793e50c7-ceed-4374-92e0-b5383df1e5a4","html_url":"https://github.com/simmsb/enum_dispatch_async","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/simmsb/enum_dispatch_async","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simmsb%2Fenum_dispatch_async","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simmsb%2Fenum_dispatch_async/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simmsb%2Fenum_dispatch_async/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simmsb%2Fenum_dispatch_async/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simmsb","download_url":"https://codeload.github.com/simmsb/enum_dispatch_async/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simmsb%2Fenum_dispatch_async/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34080026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-01-07T08:18:59.134Z","updated_at":"2026-06-08T20:32:18.121Z","avatar_url":"https://github.com/simmsb.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# enum_dispatch\n\n[![crates.io](https://img.shields.io/crates/v/enum_dispatch.svg)](https://crates.io/crates/enum_dispatch)\n[![Docs](https://docs.rs/enum_dispatch/badge.svg)](https://docs.rs/enum_dispatch/)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)]()\n\n`enum_dispatch` transforms your trait objects into concrete compound types, increasing their method call speed up to 10x.\n\n## example\n\nIf you have the following code...\n\n```rust\n// We already have defined MyImplementorA and MyImplementorB, and implemented MyBehavior for each.\n\ntrait MyBehavior {\n    fn my_trait_method(\u0026self);\n}\n\n// Any pointer type -- Box, \u0026, etc.\nlet a: Box\u003cdyn MyBehavior\u003e = Box::new(MyImplementorA::new());\n\na.my_trait_method();    //dynamic dispatch\n```\n\n...then you can improve its performance using `enum_dispatch` like this:\n\n```rust\n#[enum_dispatch]\nenum MyBehaviorEnum {\n    MyImplementorA,\n    MyImplementorB,\n}\n\n#[enum_dispatch(MyBehaviorEnum)]\ntrait MyBehavior {\n    fn my_trait_method(\u0026self);\n}\n\nlet a: MyBehaviorEnum = MyImplementorA::new().into();\n\na.my_trait_method();    //no dynamic dispatch\n```\n\nNotice the differences:\n\n1. The new enum, `MyBehaviorEnum`, whose variants are simply types implementing the trait `MyBehavior`.\n2. The new `enum_dispatch` attributes applied to the enum and trait, linking the two together.\n3. The removal of the `Box` allocation.\n4. Faster trait method calls!\n\n## how to use\n\n0. Add `enum_dispatch` as a Cargo.toml dependency, and `use enum_dispatch::enum_dispatch` in your code.\n1. Create a new enum whose variants are any in-scope trait implementors you've defined.\n2. Add an `#[enum_dispatch]` attribute to either the enum or trait definition. This will \"register\" it with the `enum_dispatch` library. Take note of the name of the enum or trait it was applied to -- we'll call it `FirstBlockName`.\n3. Add an `#[enum_dispatch(FirstBlockName)]` attribute to the remaining definition. This will \"link\" it with the previously registered definition.\n4. Update your dynamic types to use the new enum instead. You can use `.into()` from any trait implementor to automatically turn it into an enum variant.\n\n## performance\n\nMore information on performance can be found in the [docs](https://docs.rs/enum_dispatch/), and benchmarks are available in the `benches` directory.\nThe following benchmark results give a taste of what can be achieved using `enum_dispatch`.\nThey compare the speed of repeatedly accessing method calls on a `Vec` of 1024 trait objects of randomized concrete types using either `Box`ed trait objects, `\u0026` referenced trait objects, or `enum_dispatch`ed enum types.\n\n```text\ntest benches::boxdyn_homogeneous_vec       ... bench:   5,900,191 ns/iter (+/- 95,169)\ntest benches::refdyn_homogeneous_vec       ... bench:   5,658,461 ns/iter (+/- 137,128)\ntest benches::enumdispatch_homogeneous_vec ... bench:     479,630 ns/iter (+/- 3,531)\n```\n\n## bonus features\n\n### serialization compatibility\n\nWhile `enum_dispatch` was built with performance in mind, the transformations it applies make all your data structures much more visible to the compiler.\nThat means you can use [`serde`](https://crates.io/crates/serde) or other similar tools on your trait objects!\n\n### automatic `From` and `TryInto` implementations\n\n`enum_dispatch` will generate a `From` implementation for all inner types to make it easy to instantiate your custom enum.\nIn addition, it will generate a `TryInto` implementation for all inner types to make it easy to convert back into the original, unwrapped types.\n\n### attribute support\n\nYou can use use `#[cfg(...)]` attributes on `enum_dispatch` variants to conditionally include or exclude their corresponding `enum_dispatch` implementations.\nOther attributes will be passed straight through to the underlying generated enum, allowing compatibility with other procedural macros.\n\n### `no_std` support\n\n`enum_dispatch` is supported in `no_std` environments.\nIt's a great fit for embedded devices, where it's super useful to be able to allocate collections of trait objects on the stack.\n\n## tweaks and options\n\n### custom variant names\n\nBy default, `enum_dispatch` will expand each enum variant into one with a single unnamed field of the same name as the internal type.\nIf for some reason you'd like to use a custom name for a particular type in an `enum_dispatch` variant, you can do so as shown below:\n\n```rust\n#[enum_dispatch]\nenum MyTypes {\n    TypeA,\n    CustomVariantName(TypeB),\n}\n\nlet mt: MyTypes = TypeB::new().into();\nmatch mt {\n    TypeA(a) =\u003e { /* `a` is a TypeA */ },\n    CustomVariantName(b) =\u003e { /* `b` is a TypeB */ },\n}\n```\n\nCustom variant names are required for enums and traits with generic type arguments, which can also be optimized by `enum_dispatch`.\nCheck out [this generics example](tests/generics.rs) to see how that works.\n\n### specify multiple enums at once\n\nIf you want to use `enum_dispatch` to implement the same trait for multiple enums, you may specify them all in the same attribute:\n\n```rust\n#[enum_dispatch(Widgets, Tools, Gadgets)]\ntrait CommonFunctionality {\n    // ...\n}\n```\n\n### specify multiple traits at once\n\nSimilarly to above, you may use a single attribute to implement multiple traits for a single enum:\n\n```rust\n#[enum_dispatch(CommonFunctionality, WidgetFunctionality)]\nenum Widget {\n    // ...\n}\n```\n\n### generic enums and traits\n\n`enum_dispatch` can operate on enums and traits with generic parameters.\nWhen linking these, be sure to include the generic parameters in the attribute argument, like below:\n\n```rust\n#[enum_dispatch]\ntrait Foo\u003cT, U\u003e { /* ... */ }\n\n#[enum_dispatch(Foo\u003cT, U\u003e)]\nenum Bar\u003cT: Clone, U: Hash\u003e { /* ... */ }\n```\n\nThe names of corresponding generic parameters should match between the definition of the enum and trait.\n\n[This example](tests/complex_generics.rs) demonstrates this in more detail.\n\n## troubleshooting\n\n### no impls created?\n\nBe careful not to forget an attribute or mistype the name in a linking attribute.\nIf parsing is completed before a linking attribute is found, no implementations will be generated.\nDue to technical limitations of the macro system, it's impossible to properly warn the user in this scenario.\n\n### can't parse enum?\n\nTypes must be fully in scope to be usable as an enum variant. For example, the following will fail to compile:\n\n```rust\n#[enum_dispatch]\nenum Fails {\n    crate::A::TypeA,\n    crate::B::TypeB,\n}\n```\n\nThis is because the enum must be correctly parsable before macro expansion. Instead, import the types first:\n\n```rust\nuse crate::A::TypeA;\nuse crate::B::TypeB;\n\n#[enum_dispatch]\nenum Succeeds {\n    TypeA,\n    TypeB,\n}\n```\n\n## technical details\n\n`enum_dispatch` is a procedural macro that implements a trait for a fixed set of types in the form of an enum.\nThis is faster than using dynamic dispatch because type information will be \"built-in\" to each enum, avoiding a costly vtable lookup.\n\nSince `enum_dispatch` is a procedural macro, it works by processing and expanding attributed code at compile time.\nThe folowing sections explain how the example above might be transformed.\n\n### enum processing\n\nThere's no way to define an enum whose variants are actual concrete types.\nTo get around this, `enum_dispatch` rewrites its body by generating a name for each variant and using the provided type as its single tuple-style argument.\nThe name for each variant isn't particularly important for most purposes, but `enum_dispatch` will currently just use the name of the provided type.\n\n```rust\nenum MyBehaviorEnum {\n    MyImplementorA(MyImplementorA),\n    MyImplementorB(MyImplementorB),\n}\n```\n\n### trait processing\n\n`enum_dispatch` doesn't actually process annotated traits!\nHowever, it still requires access to the trait definition so it can take note of the trait's name, as well as the function signatures of any methods inside it.\n\n### trait impl creation\n\nWhenever `enum_dispatch` is able to \"link\" two definitions together, it will generate an `impl` block, implementing the trait for the enum.\nIn the above example, the linkage is completed by the `MyBehavior` trait definition, so `impl` blocks will be generated directly below that trait.\nThe generated impl block might look something like this:\n\n```rust\nimpl MyBehavior for MyBehaviorEnum {\n    fn my_trait_method(\u0026self) {\n        match self {\n            MyImplementorA(inner) =\u003e inner.my_trait_method(),\n            MyImplementorB(inner) =\u003e inner.my_trait_method(),\n        }\n    }\n}\n```\n\nAdditional trait methods would be expanded accordingly, and additional enum variants would correspond to additional match arms in each method definition.\nIt's easy to see how quickly this can become unmanageable in manually written code!\n\n### 'From' impl creation\n\nNormally, it would be impossible to initialize one of the new enum variants without knowing its name.\nHowever, with implementations of `From\u003cT\u003e` for each variant, that requirement is alleviated.\nThe generated implementations could look like the following:\n\n```rust\nimpl From\u003cMyImplementorA\u003e for MyBehaviorEnum {\n    fn from(inner: MyImplementorA) -\u003e MyBehaviorEnum {\n        MyBehaviorEnum::MyImplementorA(inner)\n    }\n}\n\nimpl From\u003cMyImplementorB\u003e for MyBehaviorEnum {\n    fn from(inner: MyImplementorB) -\u003e MyBehaviorEnum {\n        MyBehaviorEnum::MyImplementorB(inner)\n    }\n}\n```\n\nAs with above, having a large number of possible type variants would make this very difficult to maintain by hand.\n\n### registry and linkage\n\nAnyone closely familiar with writing macros will know that they must be processed locally, with no context about the surrounding source code.\nAdditionally, parsed syntax items in `syn` are `!Send` and `!Sync`.\nThis is for good reason -- with multithreaded compilation and macro expansion, there are no guarantees on the order or lifetime of a reference to any given block of code.\nUnfortunately, it also prevents referencing syntax between separate macro invocations.\n\nIn the interest of convenience, `enum_dispatch` circumvents these restrictions by converting syntax into a `String` and storing it in `once_cell` lazily initialized `Mutex\u003cHashMap\u003cString, String\u003e\u003e`s whose keys are either the trait or enum names.\n\nThere is also a similar `HashMap` dedicated to \"deferred\" links, since definitions in different files could be encountered in arbitrary orders.\nIf a linking attribute (with one argument) occurs before the corresponding registry attribute (with no arguments), the argument will be stored as a deferred link.\nOnce that argument's definition is encountered, impl blocks can be created as normal.\n\nBecause of the link deferral mechanism, it's not an error to encounter a linking attribute without being able to implement it.\n`enum_dispatch` will simply expect to find the corresponding registry attribute later in parsing.\nHowever, there's no way to insert a callback to check that all deferred links have been processed once all the original source code has been parsed, explaining the impossibility of warning the user of unlinked attributes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimmsb%2Fenum_dispatch_async","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimmsb%2Fenum_dispatch_async","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimmsb%2Fenum_dispatch_async/lists"}