{"id":17874288,"url":"https://github.com/modprog/derive-where","last_synced_at":"2025-05-16T08:06:00.931Z","repository":{"id":43044761,"uuid":"422868625","full_name":"ModProg/derive-where","owner":"ModProg","description":"Attribute proc-macro to simplify deriving standard and other traits with custom generic type bounds.","archived":false,"fork":false,"pushed_at":"2025-05-14T21:51:40.000Z","size":684,"stargazers_count":71,"open_issues_count":13,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-16T08:05:54.469Z","etag":null,"topics":["derive","macros","rust"],"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/ModProg.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,"zenodo":null}},"created_at":"2021-10-30T12:00:14.000Z","updated_at":"2025-05-14T21:51:45.000Z","dependencies_parsed_at":"2024-08-03T22:36:41.095Z","dependency_job_id":"76ba1b93-fe8c-455a-8988-7733648baa19","html_url":"https://github.com/ModProg/derive-where","commit_stats":{"total_commits":272,"total_committers":4,"mean_commits":68.0,"dds":"0.11029411764705888","last_synced_commit":"b368804be734710b393924fc3e555dc1993084e9"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ModProg%2Fderive-where","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ModProg%2Fderive-where/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ModProg%2Fderive-where/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ModProg%2Fderive-where/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ModProg","download_url":"https://codeload.github.com/ModProg/derive-where/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254493378,"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":["derive","macros","rust"],"created_at":"2024-10-28T11:08:21.498Z","updated_at":"2025-05-16T08:05:55.921Z","avatar_url":"https://github.com/ModProg.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# derive-where\n\n[![Crates.io Version](https://img.shields.io/crates/v/derive-where.svg)](https://crates.io/crates/derive-where)\n[![Live Build Status](https://img.shields.io/github/actions/workflow/status/ModProg/derive-where/test.yml?branch=main)](https://github.com/ModProg/derive-where/actions/workflows/test.yml)\n[![Docs.rs Documentation](https://img.shields.io/docsrs/derive-where)](https://docs.rs/crate/derive-where)\n\n## Description\n\nAttribute proc-macro to simplify deriving standard and other traits with\ncustom generic type bounds.\n\n## Usage\n\nThe [`derive_where`] attribute can be used just like\nstd's `#[derive(...)]` statements:\n\n```rust\n#[derive_where(Clone, Debug)]\nstruct Example\u003cT\u003e(PhantomData\u003cT\u003e);\n```\n\nThis will generate trait implementations for `Example` for any `T`,\nas opposed to std's derives, which would only implement these traits with\n`T: Trait` bound to the corresponding trait.\n\nMultiple [`derive_where`] attributes can be added to an\nitem, but only the first one must use any path qualifications.\n\n```rust\n#[derive_where::derive_where(Clone, Debug)]\n#[derive_where(Eq, PartialEq)]\nstruct Example1\u003cT\u003e(PhantomData\u003cT\u003e);\n```\n\nIf using a different package name, you must specify this:\n\n```rust\n#[derive_where(crate = derive_where_)]\n#[derive_where(Clone, Debug)]\nstruct Example\u003cT\u003e(PhantomData\u003cT\u003e);\n```\n\nIn addition, the following convenience options are available:\n\n### Generic type bounds\n\nSeparated from the list of traits with a semi-colon, types to bind to can be\nspecified. This example will restrict the implementation for `Example` to\n`T: Clone`:\n\n```rust\n#[derive_where(Clone, Debug; T)]\nstruct Example\u003cT, U\u003e(T, PhantomData\u003cU\u003e);\n```\n\nIt is also possible to specify the bounds to be applied. This will\nbind implementation for `Example` to `T: Super`:\n\n```rust\ntrait Super: Clone + Debug {}\n\n#[derive_where(Clone, Debug; T: Super)]\nstruct Example\u003cT\u003e(PhantomData\u003cT\u003e);\n```\n\nBut more complex trait bounds are possible as well.\nThe example below will restrict the [`Clone`] implementation for `Example`\nto `T::Type: Clone`:\n\n```rust\ntrait Trait {\n\ttype Type;\n}\n\nstruct Impl;\n\nimpl Trait for Impl {\n\ttype Type = i32;\n}\n\n#[derive_where(Clone, Debug; T::Type)]\nstruct Example\u003cT: Trait\u003e(T::Type);\n```\n\nAny combination of options listed here can be used to satisfy a\nspecific constrain. It is also possible to use multiple separate\nconstrain specifications when required:\n\n```rust\n#[derive_where(Clone, Debug; T)]\n#[derive_where(Eq, PartialEq; U)]\nstruct Example\u003cT, U\u003e(PhantomData\u003cT\u003e, PhantomData\u003cU\u003e);\n```\n\n### Enum default\n\nSince Rust 1.62 deriving [`Default`] on an enum is possible with the\n`#[default]` attribute. Derive-where allows this with a\n`#[derive_where(default)]` attribute:\n\n```rust\n#[derive_where(Clone, Default)]\nenum Example\u003cT\u003e {\n\t#[derive_where(default)]\n\tA(PhantomData\u003cT\u003e),\n}\n```\n\n### Skipping fields\n\nWith a `skip` or `skip_inner` attribute fields can be skipped for traits\nthat allow it, which are: [`Debug`], [`Hash`], [`Ord`], [`PartialOrd`],\n[`PartialEq`], [`Zeroize`] and [`ZeroizeOnDrop`].\n\n```rust\n#[derive_where(Debug, PartialEq; T)]\nstruct Example\u003cT\u003e(#[derive_where(skip)] T);\n\nassert_eq!(format!(\"{:?}\", Example(42)), \"Example\");\nassert_eq!(Example(42), Example(0));\n```\n\nIt is also possible to skip all fields in an item or variant if desired:\n\n```rust\n#[derive_where(Debug, PartialEq)]\n#[derive_where(skip_inner)]\nstruct StructExample\u003cT\u003e(T);\n\nassert_eq!(format!(\"{:?}\", StructExample(42)), \"StructExample\");\nassert_eq!(StructExample(42), StructExample(0));\n\n#[derive_where(Debug, PartialEq)]\nenum EnumExample\u003cT\u003e {\n\t#[derive_where(skip_inner)]\n\tA(T),\n}\n\nassert_eq!(format!(\"{:?}\", EnumExample::A(42)), \"A\");\nassert_eq!(EnumExample::A(42), EnumExample::A(0));\n```\n\nSelective skipping of fields for certain traits is also an option, both in\n`skip` and `skip_inner`. To prevent breaking invariants defined for these\ntraits, some of them can only be skipped in groups. The following groups are\navailable:\n- [`Debug`]\n- `EqHashOrd`: Skips [`Eq`], [`Hash`], [`Ord`], [`PartialOrd`] and\n  [`PartialEq`].\n- [`Hash`]\n- `Zeroize`: Skips [`Zeroize`] and [`ZeroizeOnDrop`].\n\n```rust\n#[derive_where(Debug, PartialEq)]\n#[derive_where(skip_inner(Debug))]\nstruct Example\u003cT\u003e(i32, PhantomData\u003cT\u003e);\n\nassert_eq!(format!(\"{:?}\", Example(42, PhantomData::\u003c()\u003e)), \"Example\");\nassert_ne!(\n\tExample(42, PhantomData::\u003c()\u003e),\n\tExample(0, PhantomData::\u003c()\u003e)\n);\n```\n\n### Incomparable variants/items\n\nSimilar to the `skip` attribute, `incomparable` can be used to skip variants\nor items in [`PartialEq`] and [`PartialOrd`] trait implementations, meaning\nthey will always yield `false` for `eq` and `None` for `partial_cmp`. This\nresults in all comparisons but `!=`, i.e. `==`, `\u003c`, `\u003c=`, `\u003e=` and `\u003e`,\nwith the marked variant or struct evaluating to `false`.\n\n```rust\n# use derive_where::derive_where;\n#[derive(Debug)]\n#[derive_where(PartialEq, PartialOrd)]\nenum EnumExample {\n\t#[derive_where(incomparable)]\n\tIncomparable,\n\tComparable,\n}\nassert_eq!(EnumExample::Comparable, EnumExample::Comparable);\nassert_ne!(EnumExample::Incomparable, EnumExample::Incomparable);\nassert!(!(EnumExample::Comparable \u003e= EnumExample::Incomparable));\nassert!(!(EnumExample::Comparable \u003c= EnumExample::Incomparable));\nassert!(!(EnumExample::Incomparable \u003e= EnumExample::Incomparable));\nassert!(!(EnumExample::Incomparable \u003c= EnumExample::Incomparable));\n\n#[derive(Debug)]\n#[derive_where(PartialEq, PartialOrd)]\n#[derive_where(incomparable)]\nstruct StructExample;\n\nassert_ne!(StructExample, StructExample);\nassert!(!(StructExample \u003e= StructExample));\nassert!(!(StructExample \u003c= StructExample));\n```\n\nNote that it is not possible to use `incomparable` with [`Eq`] or [`Ord`] as\nthat would break their invariants.\n\n### `Zeroize` options\n\n`Zeroize` has two options:\n- `crate`: an item-level option which specifies a path to the [`zeroize`]\n  crate in case of a re-export or rename.\n- `fqs`: a field-level option which will use fully-qualified-syntax instead\n  of calling the [`zeroize`][method@zeroize] method on `self` directly. This\n  is to avoid ambiguity between another method also called `zeroize`.\n\n```rust\n#[derive_where(Zeroize(crate = zeroize_))]\nstruct Example(#[derive_where(Zeroize(fqs))] i32);\n\nimpl Example {\n\t// If we didn't specify the `fqs` option, this would lead to a compile\n\t// error because of method ambiguity.\n\tfn zeroize(\u0026mut self) {\n\t\tself.0 = 1;\n\t}\n}\n\nlet mut test = Example(42);\n\n// Will call the struct method.\ntest.zeroize();\nassert_eq!(test.0, 1);\n\n// WIll call the `Zeroize::zeroize` method.\nZeroize::zeroize(\u0026mut test);\nassert_eq!(test.0, 0);\n```\n\n### `ZeroizeOnDrop` options\n\nIf the `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`]\nand can be implemented without [`Zeroize`], otherwise it only implements\n[`Drop`] and requires [`Zeroize`] to be implemented.\n\n[`ZeroizeOnDrop`] has one option:\n- `crate`: an item-level option which specifies a path to the [`zeroize`]\n  crate in case of a re-export or rename.\n\n```rust\n#[derive_where(ZeroizeOnDrop(crate = zeroize_))]\nstruct Example(i32);\n\nassert!(core::mem::needs_drop::\u003cExample\u003e());\n```\n\n### Supported traits\n\nThe following traits can be derived with derive-where:\n- [`Clone`]\n- [`Copy`]\n- [`Debug`]\n- [`Default`]\n- [`Eq`]\n- [`Hash`]\n- [`Ord`]\n- [`PartialEq`]\n- [`PartialOrd`]\n- [`Zeroize`]: Only available with the `zeroize` crate feature.\n- [`ZeroizeOnDrop`]: Only available with the `zeroize` crate feature. If the\n  `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`],\n  otherwise it only implements [`Drop`].\n\n### Supported items\n\nStructs, tuple structs, unions and enums are supported. Derive-where tries\nit's best to discourage usage that could be covered by std's `derive`. For\nexample unit structs and enums only containing unit variants aren't\nsupported.\n\nUnions only support [`Clone`] and [`Copy`].\n\n[`PartialOrd`] and [`Ord`] need to determine the discriminant type to\nfunction correctly. To protect against a potential future change to the\ndefault discriminant type, some compile-time validation is inserted to\nascertain that the type remains `isize`.\n\n### `no_std` support\n\n`no_std` support is provided by default.\n\n## Crate features\n\n- `nightly`: Implements [`Ord`] and [`PartialOrd`] with the help of\n  [`core::intrinsics::discriminant_value`], which is what Rust does by\n  default too. This requires a nightly version of the Rust compiler.\n- `safe`: `safe`: Uses only safe ways to access the discriminant of the enum\n  for [`Ord`] and [`PartialOrd`]. It also replaces all cases of\n  [`core::hint::unreachable_unchecked`] in [`Ord`], [`PartialEq`] and\n  [`PartialOrd`], which is what std uses, with [`unreachable`].\n- `zeroize`: Allows deriving [`Zeroize`] and [`zeroize`][method@zeroize] on\n  [`Drop`].\n- `zeroize-on-drop`: Allows deriving [`Zeroize`] and [`ZeroizeOnDrop`] and\n  requires [`zeroize`] v1.5.\n\n## MSRV\n\nThe current MSRV is 1.57 and is being checked by the CI. A change will be\naccompanied by a minor version bump. If MSRV is important to you, use\n`derive-where = \"~1.x\"` to pin a specific minor version to your crate.\n\n## Alternatives\n\n- [derivative](https://crates.io/crates/derivative) [![Crates.io](https://img.shields.io/crates/v/derivative.svg)](https://crates.io/crates/derivative)\n  is a great alternative with many options. Notably it doesn't support\n  `no_std` and requires an extra `#[derive(Derivative)]` to use.\n- [derive_bounded](https://crates.io/crates/derive_bounded) [![Crates.io](https://img.shields.io/crates/v/derive_bounded.svg)](https://crates.io/crates/derive_bounded)\n  is a new alternative still in development.\n\n## Changelog\n\nSee the [CHANGELOG] file for details.\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE] or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT license ([LICENSE-MIT] or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally\nsubmitted for inclusion in the work by you, as defined in the Apache-2.0\nlicense, shall be dual licensed as above, without any additional terms or\nconditions.\n\n[CHANGELOG]: https://github.com/ModProg/derive-where/blob/main/CHANGELOG.md\n[LICENSE-MIT]: https://github.com/ModProg/derive-where/blob/main/LICENSE-MIT\n[LICENSE-APACHE]: https://github.com/ModProg/derive-where/blob/main/LICENSE-APACHE\n[`Debug`]: https://doc.rust-lang.org/core/fmt/trait.Debug.html\n[`Default`]: https://doc.rust-lang.org/core/default/trait.Default.html\n[`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html\n[`zeroize`]: https://docs.rs/zeroize\n[`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html\n[`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html\n[method@zeroize]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html#tymethod.zeroize\n\n[`Clone`]: https://doc.rust-lang.org/core/clone/trait.Clone.html\n[`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html\n[`core::hint::unreachable_unchecked`]: https://doc.rust-lang.org/core/hint/fn.unreachable_unchecked.html\n[`core::intrinsics::discriminant_value`]: https://doc.rust-lang.org/core/intrinsics/fn.discriminant_value.html\n[`derive_where`]: https://docs.rs/derive-where/latest/derive_where/attr.derive_where.html\n[`Discriminant`]: https://doc.rust-lang.org/core/mem/struct.Discriminant.html\n[`Drop`]: https://doc.rust-lang.org/core/ops/trait.Drop.html\n[`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html\n[`i32`]: https://doc.rust-lang.org/core/primitive.i32.html\n[`isize`]: https://doc.rust-lang.org/core/primitive.isize.html\n[`Ord`]: https://doc.rust-lang.org/core/cmp/trait.Ord.html\n[`PartialEq`]: https://doc.rust-lang.org/core/cmp/trait.PartialEq.html\n[`PartialOrd`]: https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html\n[`transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html\n[`unreachable`]: https://doc.rust-lang.org/core/macro.unreachable.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodprog%2Fderive-where","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmodprog%2Fderive-where","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodprog%2Fderive-where/lists"}