assert_enum_variants-0.1.2/.cargo_vcs_info.json0000644000000001360000000000100152700ustar { "git": { "sha1": "37dadd375bc924ad39f0c443e8337a464ab1cabd" }, "path_in_vcs": "" }assert_enum_variants-0.1.2/.gitignore000064400000000000000000000000231046102023000160430ustar 00000000000000/target Cargo.lock assert_enum_variants-0.1.2/Cargo.lock0000644000000002440000000000100132430ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "assert_enum_variants" version = "0.1.2" assert_enum_variants-0.1.2/Cargo.toml0000644000000023200000000000100132630ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2024" name = "assert_enum_variants" version = "0.1.2" authors = ["Dmitrii Demenev "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A Rust macro that asserts that all variants of an enum are as provided in the macro invocation." documentation = "https://docs.rs/assert_enum_variants" readme = "README.md" keywords = [ "assert", "enum", "variants", ] categories = [ "development-tools", "development-tools::debugging", "development-tools::testing", "no-std", ] license = "MIT OR Apache-2.0" repository = "https://github.com/JohnScience/assert_enum_variants" [lib] name = "assert_enum_variants" path = "src/lib.rs" assert_enum_variants-0.1.2/Cargo.toml.orig000064400000000000000000000011321046102023000167440ustar 00000000000000[package] name = "assert_enum_variants" version = "0.1.2" edition = "2024" authors = ["Dmitrii Demenev "] description = "A Rust macro that asserts that all variants of an enum are as provided in the macro invocation." documentation = "https://docs.rs/assert_enum_variants" readme = "README.md" keywords = [ "assert", "enum", "variants", ] categories = [ "development-tools", "development-tools::debugging", "development-tools::testing", "no-std", ] license = "MIT OR Apache-2.0" repository = "https://github.com/JohnScience/assert_enum_variants" assert_enum_variants-0.1.2/README.md000064400000000000000000000077621046102023000153530ustar 00000000000000# `assert_enum_variants!` [![Crates.io](https://img.shields.io/crates/v/assert_enum_variants)](https://crates.io/crates/assert_enum_variants) [![Downloads](https://img.shields.io/crates/d/assert_enum_variants.svg)](https://crates.io/crates/assert_enum_variants) [![Documentation](https://docs.rs/assert_enum_variants/badge.svg)](https://docs.rs/assert_enum_variants) [![License](https://img.shields.io/crates/l/assert_enum_variants)](https://crates.io/crates/assert_enum_variants) [![Dependency Status](https://deps.rs/repo/github/JohnScience/assert_enum_variants/status.svg)](https://deps.rs/repo/github/JohnScience/assert_enum_variants) A Rust macro that asserts that all variants of an enum are as provided in the macro invocation. ## Example ```rust use assert_enum_variants::assert_enum_variants; #[allow(dead_code)] pub enum MyEnum { A, B(u32), C { a: String, b: u32, }, } // This will compile successfully // because all variants of `MyEnum` are accounted for. assert_enum_variants!(MyEnum, { A, B, C }); ``` It will fail to compile if any of the variants are missing or if there are any extra variants. ## Example of faliure due to missing variants ```rust,compile_fail use assert_enum_variants::assert_enum_variants; #[allow(dead_code)] pub enum MyEnum { A, B(u32), C { a: String, b: u32, }, } // This will fail to compile // because the `C` variant is missing. assert_enum_variants!(MyEnum, { A, B }); ``` ## Example of failure due to extra variants ```rust,compile_fail use assert_enum_variants::assert_enum_variants; #[allow(dead_code)] pub enum MyEnum { A, B(u32), C { a: String, b: u32, }, } // This will fail to compile // because the `D` variant is not present on `MyEnum`. assert_enum_variants!(MyEnum, { A, B, C, D }); ``` ## Reasons for using this macro Let's say you're writing some code that needs to handle all variants of an enum but there could be a situation that none of the variants fits. ```rust enum ResumeFileFormat { Pdf, Docx, Doc, } // ... impl ResumeFileFormat { fn from_extension(ext: &str) -> Option { use ResumeFileFormat::{Pdf, Docx, Doc}; let file_format: ResumeFileFormat = match ext { "pdf" => Pdf, "docx" => Docx, "doc" => Doc, _ => return None, }; Some(file_format) } } ``` Notice that due to a wildcard pattern, the compiler will not warn you if you add a new variant to the enum and forget to modify the `from_extension`. That is, unless you use the `assert_enum_variants!` macro. The following code will fail to compile if you add a new variant to the enum and forget to modify the `from_extension` function. ```rust,compile_fail use assert_enum_variants::assert_enum_variants; enum ResumeFileFormat { Pdf, Docx, Doc, Json, } // ... impl ResumeFileFormat { fn from_extension(ext: &str) -> Option { use ResumeFileFormat::{Pdf, Docx, Doc}; // This will fail to compile because the `Json` variant is missing. assert_enum_variants!(ResumeFileFormat, { Pdf, Docx, Doc }); let file_format: ResumeFileFormat = match ext { "pdf" => Pdf, "docx" => Docx, "doc" => Doc, _ => return None, }; Some(file_format) } } ``` ## Note on verbosity In the example with a wildcard pattern, it would be better to provide an attribute macro like `#[exhaustive_with_fallback]` that would add the invocation of `assert_enum_variants!` with the handled variants. However, * This would require a bit more work to implement (and I don't have time for that right now), * This would require a procedural rather than a declarative macro, * This would slow down compilation time considerably more than this macro, Due to the above reasons, I welcome you to create a separate crate that would provide such an attribute macro. assert_enum_variants-0.1.2/src/lib.rs000064400000000000000000000102401046102023000157600ustar 00000000000000#![no_std] #![doc = include_str!("../README.md")] /// This macro performs a compile-time check to validate that all variants of an enum /// are as provided in the macro invocation. /// /// # Example /// /// ```rust /// use assert_enum_variants::assert_enum_variants; /// /// #[allow(dead_code)] /// pub enum MyEnum { /// A, /// B(u32), /// C { /// a: String, /// b: u32, /// }, /// } /// /// // This will compile successfully /// // because all variants of `MyEnum` are accounted for. /// assert_enum_variants!(MyEnum, { A, B, C }); /// ``` /// /// It will fail to compile if any of the variants are missing or if there are any /// extra variants. /// /// # Example of faliure due to missing variants /// /// ```rust,compile_fail /// use assert_enum_variants::assert_enum_variants; /// /// #[allow(dead_code)] /// pub enum MyEnum { /// A, /// B(u32), /// C { /// a: String, /// b: u32, /// }, /// } /// /// // This will fail to compile /// // because the `C` variant is missing. /// assert_enum_variants!(MyEnum, { A, B }); ///``` /// /// # Example of failure due to extra variants /// /// ```rust,compile_fail /// use assert_enum_variants::assert_enum_variants; /// /// #[allow(dead_code)] /// pub enum MyEnum { /// A, /// B(u32), /// C { /// a: String, /// b: u32, /// }, /// } /// /// // This will fail to compile /// // because the `D` variant is not present on `MyEnum`. /// assert_enum_variants!(MyEnum, { A, B, C, D }); /// ``` /// /// # Reasons for using this macro /// /// Let's say you're writing some code that needs to handle all variants of an enum /// but there could be a situation that none of the variants fits. /// /// ```rust /// enum ResumeFileFormat { /// Pdf, /// Docx, /// Doc, /// } /// /// // ... /// /// impl ResumeFileFormat { /// fn from_extension(ext: &str) -> Option { /// use ResumeFileFormat::{Pdf, Docx, Doc}; /// /// let file_format: ResumeFileFormat = match ext { /// "pdf" => Pdf, /// "docx" => Docx, /// "doc" => Doc, /// _ => return None, /// }; /// /// Some(file_format) /// } /// } /// ``` /// /// Notice that due to a wildcard pattern, the compiler will not warn you if you /// add a new variant to the enum and forget to modify the `from_extension`. /// /// That is, unless you use the [`assert_enum_variants!`] macro. /// /// The following code will fail to compile if you add a new variant to the enum /// and forget to modify the `from_extension` function. /// /// ```rust,compile_fail /// use assert_enum_variants::assert_enum_variants; /// /// enum ResumeFileFormat { /// Pdf, /// Docx, /// Doc, /// Json, /// } /// /// // ... /// /// impl ResumeFileFormat { /// fn from_extension(ext: &str) -> Option { /// use ResumeFileFormat::{Pdf, Docx, Doc}; /// /// // This will fail to compile because the `Json` variant is missing. /// assert_enum_variants!(ResumeFileFormat, { Pdf, Docx, Doc }); /// /// let file_format: ResumeFileFormat = match ext { /// "pdf" => Pdf, /// "docx" => Docx, /// "doc" => Doc, /// _ => return None, /// }; /// /// Some(file_format) /// } /// } /// ``` #[macro_export] macro_rules! assert_enum_variants { ($enum:path, { $($variant:ident),* $(,)? }) => { const _: () = { #[allow(unreachable_code)] if false { #[allow(clippy::diverging_sub_expression)] let _unreachable_obj: $enum = core::unreachable!(); #[allow(unused_imports)] use $enum::{ $($variant),* }; match _unreachable_obj { $( $variant { .. } => (), )* }; } }; } } #[cfg(test)] mod tests { mod my_mod { #[allow(dead_code)] pub enum MyEnum { A, B(u32), C { a: u64, b: u32 }, } } #[allow(dead_code)] enum Never {} #[test] fn test_enum_variants() { assert_enum_variants!(my_mod::MyEnum, { A, B, C }); assert_enum_variants!(Never, {}); } }