├── .github ├── FUNDING.yml └── workflows │ └── CI.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── proc ├── Cargo.toml ├── src │ └── lib.rs └── tests │ └── size.rs ├── rustfmt.toml ├── src ├── assert_align.rs ├── assert_cfg.rs ├── assert_fields.rs ├── assert_impl.rs ├── assert_obj_safe.rs ├── assert_size.rs ├── assert_trait.rs ├── assert_type.rs ├── bool.rs ├── const_assert.rs ├── does_impl.rs ├── lib.rs └── util.rs └── tests ├── const.rs ├── eq_size.rs ├── fields.rs ├── obj_safe.rs ├── proc_size.rs ├── trait_impl.rs ├── type_eq.rs └── type_ne.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ['nvzqz'] 4 | patreon: nvzqz 5 | custom: ['https://www.paypal.me/nvzqz'] 6 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: CI 4 | 5 | jobs: 6 | check: 7 | name: Check 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v1 11 | - uses: actions-rs/toolchain@v1 12 | with: 13 | profile: minimal 14 | toolchain: stable 15 | override: true 16 | - uses: actions-rs/cargo@v1 17 | with: 18 | command: check 19 | 20 | test: 21 | name: Test Suite 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v1 25 | - uses: actions-rs/toolchain@v1 26 | with: 27 | profile: minimal 28 | toolchain: '1.37.0' 29 | override: true 30 | - uses: actions-rs/cargo@v1 31 | with: 32 | command: test 33 | args: --all-features 34 | 35 | fmt: 36 | name: Rustfmt 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v1 40 | - uses: actions-rs/toolchain@v1 41 | with: 42 | profile: minimal 43 | toolchain: stable 44 | override: true 45 | - run: rustup component add rustfmt 46 | - uses: actions-rs/cargo@v1 47 | with: 48 | command: fmt 49 | args: --all -- --check 50 | 51 | clippy: 52 | name: Clippy 53 | runs-on: ubuntu-latest 54 | steps: 55 | - uses: actions/checkout@v1 56 | - uses: actions-rs/toolchain@v1 57 | with: 58 | profile: minimal 59 | toolchain: stable 60 | override: true 61 | - run: rustup component add clippy 62 | - uses: actions-rs/cargo@v1 63 | with: 64 | command: clippy 65 | args: -- -D warnings 66 | 67 | doc: 68 | name: Rustdoc 69 | runs-on: ubuntu-latest 70 | steps: 71 | - uses: actions/checkout@v1 72 | - uses: actions-rs/toolchain@v1 73 | with: 74 | profile: minimal 75 | toolchain: nightly 76 | override: true 77 | - uses: actions-rs/cargo@v1 78 | env: 79 | RUSTFLAGS: -D warnings 80 | RUSTDOCFLAGS: --cfg docsrs 81 | with: 82 | command: doc 83 | args: --no-deps --all-features 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/rust,macos,linux,windows,visualstudiocode,intellij 3 | 4 | ### Intellij ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff: 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/dictionaries 12 | 13 | # Sensitive or high-churn files: 14 | .idea/**/dataSources/ 15 | .idea/**/dataSources.ids 16 | .idea/**/dataSources.xml 17 | .idea/**/dataSources.local.xml 18 | .idea/**/sqlDataSources.xml 19 | .idea/**/dynamic.xml 20 | .idea/**/uiDesigner.xml 21 | 22 | # Gradle: 23 | .idea/**/gradle.xml 24 | .idea/**/libraries 25 | 26 | # CMake 27 | cmake-build-debug/ 28 | 29 | # Mongo Explorer plugin: 30 | .idea/**/mongoSettings.xml 31 | 32 | ## File-based project format: 33 | *.iws 34 | 35 | ## Plugin-specific files: 36 | 37 | # IntelliJ 38 | /out/ 39 | 40 | # mpeltonen/sbt-idea plugin 41 | .idea_modules/ 42 | 43 | # JIRA plugin 44 | atlassian-ide-plugin.xml 45 | 46 | # Cursive Clojure plugin 47 | .idea/replstate.xml 48 | 49 | # Crashlytics plugin (for Android Studio and IntelliJ) 50 | com_crashlytics_export_strings.xml 51 | crashlytics.properties 52 | crashlytics-build.properties 53 | fabric.properties 54 | 55 | ### Intellij Patch ### 56 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 57 | 58 | # *.iml 59 | # modules.xml 60 | # .idea/misc.xml 61 | # *.ipr 62 | 63 | # Sonarlint plugin 64 | .idea/sonarlint 65 | 66 | ### Linux ### 67 | *~ 68 | 69 | # temporary files which can be created if a process still has a handle open of a deleted file 70 | .fuse_hidden* 71 | 72 | # KDE directory preferences 73 | .directory 74 | 75 | # Linux trash folder which might appear on any partition or disk 76 | .Trash-* 77 | 78 | # .nfs files are created when an open file is removed but is still being accessed 79 | .nfs* 80 | 81 | ### macOS ### 82 | *.DS_Store 83 | .AppleDouble 84 | .LSOverride 85 | 86 | # Icon must end with two \r 87 | Icon 88 | 89 | # Thumbnails 90 | ._* 91 | 92 | # Files that might appear in the root of a volume 93 | .DocumentRevisions-V100 94 | .fseventsd 95 | .Spotlight-V100 96 | .TemporaryItems 97 | .Trashes 98 | .VolumeIcon.icns 99 | .com.apple.timemachine.donotpresent 100 | 101 | # Directories potentially created on remote AFP share 102 | .AppleDB 103 | .AppleDesktop 104 | Network Trash Folder 105 | Temporary Items 106 | .apdisk 107 | 108 | ### Rust ### 109 | # Generated by Cargo 110 | # will have compiled files and executables 111 | /target/ 112 | 113 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 114 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 115 | Cargo.lock 116 | 117 | # These are backup files generated by rustfmt 118 | **/*.rs.bk 119 | 120 | ### VisualStudioCode ### 121 | .vscode/* 122 | !.vscode/settings.json 123 | !.vscode/tasks.json 124 | !.vscode/launch.json 125 | !.vscode/extensions.json 126 | .history 127 | 128 | ### Windows ### 129 | # Windows thumbnail cache files 130 | Thumbs.db 131 | ehthumbs.db 132 | ehthumbs_vista.db 133 | 134 | # Folder config file 135 | Desktop.ini 136 | 137 | # Recycle Bin used on file shares 138 | $RECYCLE.BIN/ 139 | 140 | # Windows Installer files 141 | *.cab 142 | *.msi 143 | *.msm 144 | *.msp 145 | 146 | # Windows shortcuts 147 | *.lnk 148 | 149 | # End of https://www.gitignore.io/api/rust,macos,linux,windows,visualstudiocode,intellij 150 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog [![Crates.io][crate-badge]][crate] 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog] and this project adheres to 5 | [Semantic Versioning]. 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.1.0] - 2019-11-03 10 | ### Added 11 | - `assert_impl_any!` macro 12 | - `assert_impl_one!` macro 13 | - `assert_trait_sub_all!` macro 14 | - `assert_trait_super_all!` macro 15 | - Frequently asked questions to `README.md` 16 | 17 | ### Fixed 18 | - `assert_eq_size_val!`, `const_assert_eq!`, and `const_assert_ne!` to export 19 | their local inner macros. Not having this prevented them from working when 20 | `use`d or called directly via `static_assertions::macro!(...)` 21 | 22 | ### Removed 23 | - Unused `_assert_obj_safe!` from pre-1.0 24 | 25 | ## [1.0.0] - 2019-10-02 26 | ### Added 27 | - `assert_eq_align!` macro 28 | 29 | ### Removed 30 | - **[breaking]** Labels from macros that needed them 🎉 31 | - Made possible by [`const _`] in Rust 1.37 32 | - **[breaking]** `assert_impl!` macro 33 | 34 | ### Fixed 35 | - `assert_fields!` now works for `enum` types with multiple variants 36 | 37 | ### Changed 38 | - **[breaking]** `const_assert!` macro to only take one expression 39 | - Reasoning: when custom error messages are added in the future (via 40 | [`assert!`]), having the macro allow for multiple comma-separated 41 | expressions may lead to ambiguity 42 | - **[breaking]** Trait assertions to use `Type: Trait` syntax 43 | - **[breaking]** Field assertions to use `Type: field1, field2` syntax 44 | - **[breaking]** Renamed `assert_{ne,eq}_type!` to `assert_type_{ne,eq}_all!` 45 | 46 | ## [0.3.4] - 2019-06-12 47 | ### Changed 48 | - Aliased `assert_impl!` to `assert_impl_all!` and deprecated `assert_impl!` 49 | 50 | ### Added 51 | - `assert_impl_all!` as replacement to `assert_impl!` 52 | - `assert_not_impl_all!` and `assert_not_impl_any!` macro counterparts to 53 | `assert_impl_all!` 54 | 55 | ### Fixed 56 | - `assert_eq_type!` now works with types involving lifetimes 57 | 58 | ## [0.3.3] - 2019-06-12 59 | ### Added 60 | - `const_assert_ne!` macro counterpart to `const_assert_eq!` 61 | 62 | ### Fixed 63 | - `assert_eq_type!` would pass when types can coerce via `Deref`, such as with 64 | `str` and `String` 65 | 66 | ## [0.3.2] - 2019-05-15 67 | ### Added 68 | - A `assert_eq_type!` macro that allows for checking whether inputs are the same 69 | concrete type 70 | - A `assert_ne_type!` macro for checking whether inputs all refer to different 71 | types 72 | 73 | ### Fixed 74 | - `const_assert!` now only takes `bool` values whereas integer (or other type) 75 | values could previously be passed 76 | 77 | ## [0.3.1] - 2018-11-15 78 | ### Fixed 79 | - Macros that refer to other internal macros can now be imported when compiling 80 | for Rust 2018 ([issue 81 | #10](https://github.com/nvzqz/static-assertions-rs/issues/10)) 82 | 83 | ## [0.3.0] - 2018-11-14 84 | ### Changed 85 | - Bumped minimum supported (automatically tested) Rust version to 1.24.0 86 | - Moved message parameter for `assert_cfg!()` to last argument position, making 87 | it consistent with other macros 88 | 89 | ### Removed 90 | - No need to use `macro!(label; ...)` syntax when compiling on nightly Rust and 91 | enabling the `nightly` feature flag 92 | 93 | ## [0.2.5] - 2017-12-12 94 | ### Changed 95 | - `assert_eq_size_ptr` wraps its code inside of a closure, ensuring that the 96 | unsafe code inside never runs 97 | - Clippy no longer warns about `unneeded_field_pattern` within `assert_fields` 98 | 99 | ### Added 100 | - Much better documentation with test examples that are guaranteed to fail at 101 | compile-time 102 | 103 | ### Removed 104 | - Removed testing features; compile failure tests are now done via doc tests 105 | 106 | ## [0.2.4] - 2017-12-11 107 | ### Removed 108 | - Removed the actual call to `mem::transmute` while still utilizing it for size 109 | verification ([Simon Sapin], [#5]) 110 | 111 | ### Added 112 | - `assert_cfg` macro that asserts that the given configuration is set 113 | - `assert_fields` macro to assert that a struct type or enum variant has a given 114 | field 115 | 116 | ### Fixed 117 | - Allow more generics flexibility in `assert_impl` 118 | 119 | ## [0.2.3] - 2017-08-24 120 | ### Fixed 121 | - Trailing commas are now allowed 122 | 123 | ### Removed 124 | - Removed clippy warnings 125 | 126 | ## [0.2.2] - 2017-08-13 127 | ### Added 128 | - Added `assert_impl` macro to ensure a type implements a given set of traits 129 | 130 | ## [0.2.1] - 2017-08-13 131 | ### Added 132 | - Added `assert_obj_safe` macro for ensuring that a trait is object-safe 133 | 134 | ## [0.2.0] - 2017-08-12 135 | ### Added 136 | - Added `assert_eq_size_ptr` macro 137 | 138 | ### Fixed 139 | - Allow `assert_eq_size`, `const_assert`, and `const_assert_eq` in non-function 140 | contexts via providing a unique label [#1] 141 | 142 | ### Removed 143 | - **[Breaking]** Semicolon-separated `assert_eq_size` is no longer allowed 144 | 145 | ## [0.1.1] - 2017-08-12 146 | ### Added 147 | - Added `const_assert_eq` macro 148 | 149 | ## 0.1.0 - 2017-08-12 150 | 151 | Initial release 152 | 153 | [Simon Sapin]: https://github.com/SimonSapin 154 | 155 | [`assert!`]: https://doc.rust-lang.org/stable/std/macro.assert.html 156 | [`const _`]: https://github.com/rust-lang/rfcs/blob/master/text/2526-const-wildcard.md 157 | 158 | [#1]: https://github.com/nvzqz/static-assertions-rs/issues/1 159 | [#5]: https://github.com/nvzqz/static-assertions-rs/pull/5 160 | 161 | [crate]: https://crates.io/crates/static_assertions 162 | [crate-badge]: https://img.shields.io/crates/v/static_assertions.svg 163 | 164 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 165 | [Semantic Versioning]: http://semver.org/spec/v2.0.0.html 166 | 167 | [Unreleased]: https://github.com/nvzqz/static-assertions-rs/compare/v1.1.0...HEAD 168 | [1.1.0]: https://github.com/nvzqz/static-assertions-rs/compare/v1.0.0...v1.1.0 169 | [1.0.0]: https://github.com/nvzqz/static-assertions-rs/compare/v0.3.4...v1.0.0 170 | [0.3.4]: https://github.com/nvzqz/static-assertions-rs/compare/v0.3.3...v0.3.4 171 | [0.3.3]: https://github.com/nvzqz/static-assertions-rs/compare/v0.3.2...v0.3.3 172 | [0.3.2]: https://github.com/nvzqz/static-assertions-rs/compare/v0.3.1...v0.3.2 173 | [0.3.1]: https://github.com/nvzqz/static-assertions-rs/compare/v0.3.0...v0.3.1 174 | [0.3.0]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.5...v0.3.0 175 | [0.2.5]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.4...v0.2.5 176 | [0.2.4]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.3...v0.2.4 177 | [0.2.3]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.2...v0.2.3 178 | [0.2.2]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.1...v0.2.2 179 | [0.2.1]: https://github.com/nvzqz/static-assertions-rs/compare/v0.2.0...v0.2.1 180 | [0.2.0]: https://github.com/nvzqz/static-assertions-rs/compare/v0.1.1...v0.2.0 181 | [0.1.1]: https://github.com/nvzqz/static-assertions-rs/compare/v0.1.0...v0.1.1 182 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_assertions" 3 | version = "1.1.0" 4 | authors = ["Nikolai Vazquez"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | homepage = "https://github.com/nvzqz/static-assertions-rs" 8 | repository = "https://github.com/nvzqz/static-assertions-rs" 9 | documentation = "https://docs.rs/static_assertions/" 10 | categories = ["no-std", "rust-patterns", "development-tools::testing"] 11 | keywords = ["assert", "static", "testing"] 12 | description = "Compile-time assertions to ensure that invariants are met." 13 | include = ["Cargo.toml", "src/**/*.rs", "README.md", "CHANGELOG.md", "LICENSE*"] 14 | 15 | [dependencies.proc_static_assertions] 16 | version = "0.0.0" 17 | path = "proc" 18 | optional = true 19 | 20 | [workspace] 21 | members = ["proc"] 22 | 23 | [features] 24 | nightly = [] 25 | proc = ["proc_static_assertions"] 26 | 27 | [badges] 28 | maintenance = { status = "actively-maintained" } 29 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nikolai Vazquez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs) 2 | 3 |
4 | 5 | Crates.io 6 | Downloads 7 | 8 | 9 | Build Status 10 | 11 | rustc ^1.37.0 12 |
13 | 14 | Become a Patron! 15 | 16 | 17 | Buy me a coffee 18 | 19 |
20 | 21 | Compile-time assertions for Rust, brought to you by 22 | [Nikolai Vazquez](https://twitter.com/NikolaiVazquez). 23 | 24 | This library lets you ensure correct assumptions about constants, types, and 25 | more. See the [docs] and [FAQ](#faq) for more info! 26 | 27 | ## Installation 28 | 29 | This crate is available 30 | [on crates.io](https://crates.io/crates/static_assertions) and can be used by 31 | adding the following to your project's 32 | [`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html): 33 | 34 | ```toml 35 | [dependencies] 36 | static_assertions = "1.1.0" 37 | ``` 38 | 39 | and this to your crate root (`main.rs` or `lib.rs`): 40 | 41 | ```rust 42 | #[macro_use] 43 | extern crate static_assertions; 44 | ``` 45 | 46 | ## Usage 47 | 48 | This crate exposes the following macros: 49 | - [`assert_cfg!`] 50 | - [`assert_eq_align!`] 51 | - [`assert_eq_size!`] 52 | - [`assert_eq_size_ptr!`] 53 | - [`assert_eq_size_val!`] 54 | - [`assert_fields!`] 55 | - [`assert_impl_all!`] 56 | - [`assert_impl_any!`] 57 | - [`assert_impl_one!`] 58 | - [`assert_not_impl_all!`] 59 | - [`assert_not_impl_any!`] 60 | - [`assert_obj_safe!`] 61 | - [`assert_trait_sub_all!`] 62 | - [`assert_trait_super_all!`] 63 | - [`assert_type_eq_all!`] 64 | - [`assert_type_ne_all!`] 65 | - [`const_assert!`] 66 | - [`const_assert_eq!`] 67 | - [`const_assert_ne!`] 68 | 69 | ## FAQ 70 | 71 | - **Q:** When would I want to use this? 72 | 73 | **A:** This library is useful for when wanting to ensure properties of 74 | constants, types, and traits. 75 | 76 | Basic examples: 77 | 78 | - With the release of 1.39, `str::len` can be called in a `const` 79 | context. Using [`const_assert!`], one can check that a string generated from 80 | elsewhere is of a given size: 81 | 82 | ```rust 83 | const DATA: &str = include_str!("path/to/string.txt"); 84 | 85 | const_assert!(DATA.len() < 512); 86 | ``` 87 | 88 | - Have a type that absolutely must implement certain traits? With 89 | [`assert_impl_all!`], one can ensure this: 90 | 91 | ```rust 92 | struct Foo { 93 | value: // ... 94 | } 95 | 96 | assert_impl_all!(Foo: Send, Sync); 97 | ``` 98 | 99 | - **Q:** How can I contribute? 100 | 101 | **A:** A couple of ways! You can: 102 | 103 | - Attempt coming up with some form of static analysis that you'd like to see 104 | implemented. Create a [new issue] and describe how you'd imagine your 105 | assertion to work, with example code to demonstrate. 106 | 107 | - Implement your own static assertion and create a [pull request]. 108 | 109 | - Give feedback. What are some pain points? Where is it unpleasant? 110 | 111 | - Write docs. If you're familiar with how this library works, sharing your 112 | knowledge with the rest its users would be great! 113 | 114 | - **Q:** Will this affect my compiled binary? 115 | 116 | **A:** Nope! There is zero runtime cost to using this because all checks are 117 | at compile-time, and so no code is emitted to run. 118 | 119 | - **Q:** Will this affect my compile times? 120 | 121 | **A:** Likely not by anything perceivable. If this is a concern, this library 122 | can be put in `dev-dependencies`: 123 | 124 | ```toml 125 | [dev-dependencies] 126 | static_assertions = "1.1.0" 127 | ``` 128 | 129 | and then assertions can be conditionally run behind `#[cfg(test)]`: 130 | 131 | ```rust 132 | #[cfg(test)] 133 | const_assert_eq!(MEANING_OF_LIFE, 42); 134 | ``` 135 | 136 | However, the assertions will only be checked when running `cargo test`. This 137 | somewhat defeats the purpose of catching false static conditions up-front with 138 | a compilation failure. 139 | 140 | - **Q:** What is `const _`? 141 | 142 | **A:** It's a way of creating an unnamed constant. This is used so that macros 143 | can be called from a global scope without requiring a scope-unique label. This 144 | library makes use of the side effects of evaluating the `const` expression. 145 | See the feature's 146 | [tracking issue](https://github.com/rust-lang/rust/issues/54912) 147 | and 148 | [issue #1](https://github.com/nvzqz/static-assertions-rs/issues/1) 149 | for more info. 150 | 151 | ## Changes 152 | 153 | See [`CHANGELOG.md`](https://github.com/nvzqz/static-assertions-rs/blob/master/CHANGELOG.md) 154 | for a complete list of what has changed from one version to another. 155 | 156 | ## License 157 | 158 | This project is released under either: 159 | 160 | - [MIT License](https://github.com/nvzqz/static-assertions-rs/blob/master/LICENSE-MIT) 161 | 162 | - [Apache License (Version 2.0)](https://github.com/nvzqz/static-assertions-rs/blob/master/LICENSE-APACHE) 163 | 164 | at your choosing. 165 | 166 | [new issue]: https://github.com/nvzqz/static-assertions-rs/issues/new 167 | [pull request]: https://github.com/nvzqz/static-assertions-rs/pulls 168 | [docs]: https://docs.rs/static_assertions 169 | 170 | [`assert_cfg!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_cfg.html 171 | [`assert_eq_align!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_eq_align.html 172 | [`assert_eq_size!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_eq_size.html 173 | [`assert_eq_size_ptr!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_eq_size_ptr.html 174 | [`assert_eq_size_val!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_eq_size_val.html 175 | [`assert_fields!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_fields.html 176 | [`assert_impl_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_impl_all.html 177 | [`assert_impl_any!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_impl_any.html 178 | [`assert_impl_one!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_impl_one.html 179 | [`assert_not_impl_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_not_impl_all.html 180 | [`assert_not_impl_any!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_not_impl_any.html 181 | [`assert_obj_safe!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_obj_safe.html 182 | [`assert_trait_sub_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_trait_sub_all.html 183 | [`assert_trait_super_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_trait_super_all.html 184 | [`assert_type_eq_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_type_eq_all.html 185 | [`assert_type_ne_all!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.assert_type_ne_all.html 186 | [`const_assert!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.const_assert.html 187 | [`const_assert_eq!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.const_assert_eq.html 188 | [`const_assert_ne!`]: https://docs.rs/static_assertions/1.1.0/static_assertions/macro.const_assert_ne.html 189 | -------------------------------------------------------------------------------- /proc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proc_static_assertions" 3 | version = "0.0.0" 4 | authors = ["Nikolai Vazquez"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "../README.md" 7 | homepage = "https://github.com/nvzqz/static-assertions-rs" 8 | repository = "https://github.com/nvzqz/static-assertions-rs" 9 | documentation = "https://docs.rs/proc_static_assertions/" 10 | categories = ["no-std", "rust-patterns", "development-tools::testing"] 11 | keywords = ["assert", "static", "testing"] 12 | description = "Compile-time assertions via procedural macros." 13 | include = ["Cargo.toml", "src/**/*.rs", "README.md", "CHANGELOG.md", "LICENSE*"] 14 | 15 | [lib] 16 | proc-macro = true 17 | 18 | [badges] 19 | travis-ci = { repository = "nvzqz/static-assertions-rs" } 20 | is-it-maintained-open-issues = { repository = "nvzqz/static-assertions-rs" } 21 | is-it-maintained-issue-resolution = { repository = "nvzqz/static-assertions-rs" } 22 | maintenance = { status = "passively-maintained" } 23 | 24 | [features] 25 | nightly = [] 26 | -------------------------------------------------------------------------------- /proc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs) 2 | //! 3 | //!
4 | //! 5 | //! Downloads 6 | //! 7 | //! 8 | //! Build Status 9 | //! 10 | //!

11 | //!
12 | //! 13 | //! Procedural macro [compile-time] assertions as an extension of 14 | //! [`static_assertions`]. 15 | //! 16 | //! # Usage 17 | //! 18 | //! There's two main ways of using this crate: as a direct dependency or 19 | //! indirect dependency (via [`static_assertions`]). 20 | //! 21 | //! ## Direct Dependency 22 | //! 23 | //! This crate is available [on crates.io][crate] and can be used by adding the 24 | //! following to your project's [`Cargo.toml`]: 25 | //! 26 | //! ```toml 27 | //! [dependencies] 28 | //! proc_static_assertions = "0.0.0" 29 | //! ``` 30 | //! 31 | //! and this to your crate root (`main.rs` or `lib.rs`): 32 | //! 33 | //! ``` 34 | //! #[macro_use] 35 | //! extern crate proc_static_assertions; 36 | //! # fn main() {} 37 | //! ``` 38 | //! 39 | //! ## Indirect Dependency 40 | //! 41 | //! Add the following to your project's [`Cargo.toml`]: 42 | //! 43 | //! ```toml 44 | //! [dependencies] 45 | //! static_assertions = { version = "1.1.0", features = ["proc"] } 46 | //! ``` 47 | //! 48 | //! and this to your crate root (`main.rs` or `lib.rs`): 49 | //! 50 | //! ```ignore 51 | //! #[macro_use] 52 | //! extern crate static_assertions; 53 | //! ``` 54 | //! 55 | //! This will also import all macros in `proc_static_assertions`. 56 | //! 57 | //! # Donate 58 | //! 59 | //! This project is made freely available (as in free beer), but unfortunately 60 | //! not all beer is free! So, if you would like to buy me a beer (or coffee or 61 | //! *more*), then consider supporting my work that's benefited your project 62 | //! and thousands of others. 63 | //! 64 | //! 65 | //! Become a Patron! 66 | //! 67 | //! 68 | //! Buy me a coffee 69 | //! 70 | //! 71 | //! [`static_assertions`]: https://github.com/nvzqz/static-assertions-rs 72 | //! [crate]: https://crates.io/crates/static_assertions 73 | //! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html 74 | //! [compile-time]: https://en.wikipedia.org/wiki/Compile_time 75 | 76 | #![doc(html_root_url = "https://docs.rs/proc_static_assertions/0.0.0")] 77 | #![doc( 78 | html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png" 79 | )] 80 | #![deny(missing_docs)] 81 | 82 | extern crate proc_macro; 83 | use proc_macro::TokenStream; 84 | 85 | /// Statically assert aspects of types, traits, and more. 86 | /// 87 | /// This currently does nothing. Create an issue if you have ideas for what this 88 | /// could do! 89 | #[proc_macro_attribute] 90 | pub fn assert(_attr: TokenStream, _item: TokenStream) -> TokenStream { 91 | TokenStream::new() 92 | } 93 | -------------------------------------------------------------------------------- /proc/tests/size.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate proc_static_assertions; 3 | 4 | #[assert(size == 4, align == 4)] 5 | struct Foo { 6 | value: i32, 7 | } 8 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | hard_tabs = false 3 | tab_spaces = 4 4 | newline_style = "Unix" 5 | use_small_heuristics = "Default" 6 | reorder_imports = true 7 | reorder_modules = true 8 | remove_nested_parens = true 9 | fn_args_layout = "Tall" 10 | edition = "2018" 11 | merge_derives = true 12 | use_try_shorthand = false 13 | use_field_init_shorthand = true 14 | force_explicit_abi = true 15 | print_misformatted_file_names = true 16 | -------------------------------------------------------------------------------- /src/assert_align.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that the types' alignments are equal. 2 | /// 3 | /// This is useful when ensuring that pointer arithmetic is done correctly, or 4 | /// when [FFI] requires a type to have the same alignment as some foreign type. 5 | /// 6 | /// # Examples 7 | /// 8 | /// A `usize` has the same alignment as any pointer type: 9 | /// 10 | /// ``` 11 | /// # #[macro_use] extern crate static_assertions; fn main() {} 12 | /// assert_align_eq!(usize, *const u8, *mut u8); 13 | /// ``` 14 | /// 15 | /// The following passes because `[i32; 4]` has the same alignment as `i32`: 16 | /// 17 | /// ``` 18 | /// # #[macro_use] extern crate static_assertions; fn main() {} 19 | /// assert_align_eq!([i32; 4], i32); 20 | /// ``` 21 | /// 22 | /// The following example fails to compile because `i32x4` explicitly has 4 23 | /// times the alignment as `[i32; 4]`: 24 | /// 25 | /// ```compile_fail 26 | /// # #[macro_use] extern crate static_assertions; fn main() {} 27 | /// # #[allow(non_camel_case_types)] 28 | /// #[repr(align(16))] 29 | /// struct i32x4([i32; 4]); 30 | /// 31 | /// assert_align_eq!(i32x4, [i32; 4]); 32 | /// ``` 33 | /// 34 | /// [FFI]: https://en.wikipedia.org/wiki/Foreign_function_interface 35 | #[macro_export(local_inner_macros)] 36 | macro_rules! assert_align_eq { 37 | ($x:ty, $($y:ty),+ $(,)?) => { 38 | const _: fn() = || { 39 | use $crate::_core::mem::align_of; 40 | const_assert_eq_usize!(align_of::<$x>() $(, align_of::<$y>())+); 41 | }; 42 | }; 43 | } 44 | 45 | /// Asserts that the types' alignments are equal. 46 | /// 47 | /// This macro has been deprecated in favor of 48 | /// [`assert_align_eq!`](macro.assert_align_eq.html). 49 | #[deprecated( 50 | since = "1.2.0", 51 | note = "Please use the 'assert_align_eq' macro instead" 52 | )] 53 | #[macro_export(local_inner_macros)] 54 | macro_rules! assert_eq_align { 55 | ($($t:tt)*) => { 56 | assert_align_eq!($($t)*); 57 | }; 58 | } 59 | 60 | /// Asserts that the types' alignments are **not** equal. 61 | /// 62 | /// # Examples 63 | /// 64 | /// A `u8` does not have the same alignment as a pointer: 65 | /// 66 | /// ``` 67 | /// # #[macro_use] extern crate static_assertions; fn main() {} 68 | /// assert_align_ne!(u8, *const u8); 69 | /// ``` 70 | /// 71 | /// The following example fails to compile because a `usize` has the same 72 | /// alignment as a pointer: 73 | /// 74 | /// ```compile_fail 75 | /// # #[macro_use] extern crate static_assertions; fn main() {} 76 | /// assert_align_ne!(*const u8, usize); 77 | /// ``` 78 | #[macro_export(local_inner_macros)] 79 | macro_rules! assert_align_ne { 80 | ($x:ty, $($y:ty),+ $(,)?) => { 81 | const _: fn() = || { 82 | use $crate::_core::mem::align_of; 83 | const_assert_ne!(align_of::<$x>() $(, align_of::<$y>())+); 84 | }; 85 | }; 86 | } 87 | 88 | /// Asserts that the types' alignments are less than each other. 89 | /// 90 | /// # Examples 91 | /// 92 | /// A `u8` has smaller alignment than `u16`, which has smaller alignment than 93 | /// a pointer: 94 | /// 95 | /// ``` 96 | /// # #[macro_use] extern crate static_assertions; fn main() {} 97 | /// assert_align_lt!(u8, u16, *const u8); 98 | /// ``` 99 | /// 100 | /// The following example fails to compile because a `usize` has the same 101 | /// alignment as a pointer: 102 | /// 103 | /// ```compile_fail 104 | /// # #[macro_use] extern crate static_assertions; fn main() {} 105 | /// assert_align_lt!(*const u8, usize); 106 | /// ``` 107 | #[macro_export(local_inner_macros)] 108 | macro_rules! assert_align_lt { 109 | ($x:ty, $($y:ty),+ $(,)?) => { 110 | const _: fn() = || { 111 | use $crate::_core::mem::align_of; 112 | const_assert_lt!(align_of::<$x>() $(, align_of::<$y>())+); 113 | }; 114 | }; 115 | } 116 | 117 | /// Asserts that the types' alignments are less than or equal to each other. 118 | /// 119 | /// # Examples 120 | /// 121 | /// A `u8` and `i8` have smaller alignment than any pointer type: 122 | /// 123 | /// ``` 124 | /// # #[macro_use] extern crate static_assertions; fn main() {} 125 | /// assert_align_le!(u8, i8, *const u8); 126 | /// ``` 127 | /// 128 | /// The following example fails to compile because a `usize` has greater 129 | /// alignment than `u8`: 130 | /// 131 | /// ```compile_fail 132 | /// # #[macro_use] extern crate static_assertions; fn main() {} 133 | /// assert_align_le!(usize, u8); 134 | /// ``` 135 | #[macro_export(local_inner_macros)] 136 | macro_rules! assert_align_le { 137 | ($x:ty, $($y:ty),+ $(,)?) => { 138 | const _: fn() = || { 139 | use $crate::_core::mem::align_of; 140 | const_assert_le!(align_of::<$x>() $(, align_of::<$y>())+); 141 | }; 142 | }; 143 | } 144 | 145 | /// Asserts that the types' alignments are greater than each other. 146 | /// 147 | /// # Examples 148 | /// 149 | /// A pointer has greater alignment than `u16`, which has greater alignment than 150 | /// `u8`: 151 | /// 152 | /// ``` 153 | /// # #[macro_use] extern crate static_assertions; fn main() {} 154 | /// assert_align_gt!(*const u8, u16, u8); 155 | /// ``` 156 | /// 157 | /// The following example fails to compile because a `usize` has the same 158 | /// alignment as a pointer: 159 | /// 160 | /// ```compile_fail 161 | /// # #[macro_use] extern crate static_assertions; fn main() {} 162 | /// assert_align_gt!(*const u8, usize); 163 | /// ``` 164 | #[macro_export(local_inner_macros)] 165 | macro_rules! assert_align_gt { 166 | ($x:ty, $($y:ty),+ $(,)?) => { 167 | const _: fn() = || { 168 | use $crate::_core::mem::align_of; 169 | const_assert_gt!(align_of::<$x>() $(, align_of::<$y>())+); 170 | }; 171 | }; 172 | } 173 | 174 | /// Asserts that the types' alignments are greater than or equal to each other. 175 | /// 176 | /// # Examples 177 | /// 178 | /// A pointer has greater alignment than `u8` and `i8`: 179 | /// 180 | /// ``` 181 | /// # #[macro_use] extern crate static_assertions; fn main() {} 182 | /// assert_align_ge!(*const u8, u8, i8); 183 | /// ``` 184 | /// 185 | /// The following example fails to compile because a `u8` has smaller alignment 186 | /// than `usize`: 187 | /// 188 | /// ```compile_fail 189 | /// # #[macro_use] extern crate static_assertions; fn main() {} 190 | /// assert_align_ge!(u8, usize); 191 | /// ``` 192 | #[macro_export(local_inner_macros)] 193 | macro_rules! assert_align_ge { 194 | ($x:ty, $($y:ty),+ $(,)?) => { 195 | const _: fn() = || { 196 | use $crate::_core::mem::align_of; 197 | const_assert_ge!(align_of::<$x>() $(, align_of::<$y>())+); 198 | }; 199 | }; 200 | } 201 | -------------------------------------------------------------------------------- /src/assert_cfg.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that a given configuration is set. 2 | /// 3 | /// # Examples 4 | /// 5 | /// A project will simply fail to compile if the given configuration is not set. 6 | /// 7 | /// ``` 8 | /// # #[macro_use] extern crate static_assertions; fn main() {} 9 | /// // We're not masochists 10 | /// # #[cfg(not(target_pointer_width = "16"))] // Just in case 11 | /// assert_cfg!(not(target_pointer_width = "16")); 12 | /// ``` 13 | /// 14 | /// If a project does not support a set of configurations, you may want to 15 | /// report why. There is the option of providing a compile error message string: 16 | /// 17 | /// ``` 18 | /// # #[macro_use] extern crate static_assertions; fn main() {} 19 | /// # #[cfg(any(unix, windows))] 20 | /// assert_cfg!(any(unix, windows), "There is only support for Unix or Windows"); 21 | /// 22 | /// // User needs to specify a database back-end 23 | /// # #[cfg(target_pointer_width = "0")] // Impossible 24 | /// assert_cfg!(all(not(all(feature = "mysql", feature = "mongodb")), 25 | /// any( feature = "mysql", feature = "mongodb")), 26 | /// "Must exclusively use MySQL or MongoDB as database back-end"); 27 | /// ``` 28 | /// 29 | /// Some configurations are impossible. For example, we can't be compiling for 30 | /// both macOS _and_ Windows simultaneously: 31 | /// 32 | /// ```compile_fail 33 | /// # #[macro_use] extern crate static_assertions; fn main() {} 34 | /// assert_cfg!(all(target_os = "macos", 35 | /// target_os = "windows"), 36 | /// "No, that's not how it works! ಠ_ಠ"); 37 | /// ``` 38 | #[macro_export] 39 | macro_rules! assert_cfg { 40 | () => {}; 41 | ($($cfg:meta)+, $msg:expr $(,)?) => { 42 | #[cfg(not($($cfg)+))] 43 | compile_error!($msg); 44 | }; 45 | ($($cfg:tt)*) => { 46 | #[cfg(not($($cfg)*))] 47 | compile_error!(concat!("Cfg does not pass: ", stringify!($($cfg)*))); 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/assert_fields.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that the type has the given fields. 2 | /// 3 | /// # Examples 4 | /// 5 | /// One common use case is when types have fields defined multiple times as a 6 | /// result of `#[cfg]`. This can be an issue when exposing a public API. 7 | /// 8 | /// ``` 9 | /// # #[macro_use] extern crate static_assertions; 10 | /// pub struct Ty { 11 | /// #[cfg(windows)] 12 | /// pub val1: u8, 13 | /// #[cfg(not(windows))] 14 | /// pub val1: usize, 15 | /// 16 | /// #[cfg(unix)] 17 | /// pub val2: u32, 18 | /// #[cfg(not(unix))] 19 | /// pub val2: usize, 20 | /// } 21 | /// 22 | /// // Always have `val2` regardless of OS 23 | /// assert_fields!(Ty: val2); 24 | /// ``` 25 | /// 26 | /// This macro even works with `enum` variants: 27 | /// 28 | /// ``` 29 | /// # #[macro_use] extern crate static_assertions; fn main() {} 30 | /// enum Data { 31 | /// Val { 32 | /// id: i32, 33 | /// name: String, 34 | /// bytes: [u8; 128], 35 | /// }, 36 | /// Ptr(*const u8), 37 | /// } 38 | /// 39 | /// assert_fields!(Data::Val: id, bytes); 40 | /// ``` 41 | /// 42 | /// The following example fails to compile because [`Range`] does not have a field named `middle`: 43 | /// 44 | /// ```compile_fail 45 | /// # #[macro_use] extern crate static_assertions; fn main() {} 46 | /// use std::ops::Range; 47 | /// 48 | /// assert_fields!(Range: middle); 49 | /// ``` 50 | /// 51 | /// [`Range`]: https://doc.rust-lang.org/std/ops/struct.Range.html 52 | #[macro_export] 53 | macro_rules! assert_fields { 54 | ($t:ident::$v:ident: $($f:ident),+) => { 55 | #[allow(unknown_lints, unneeded_field_pattern)] 56 | const _: fn() = || { 57 | #[allow(dead_code, unreachable_patterns)] 58 | fn assert(value: $t) { 59 | match value { 60 | $($t::$v { $f: _, .. } => {},)+ 61 | _ => {} 62 | } 63 | } 64 | }; 65 | }; 66 | ($t:path: $($f:ident),+) => { 67 | #[allow(unknown_lints, unneeded_field_pattern)] 68 | const _: fn() = || { 69 | $(let $t { $f: _, .. };)+ 70 | }; 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /src/assert_impl.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that the type implements exactly one in a set of traits. 2 | /// 3 | /// Related: 4 | /// - [`assert_impl_any!`] 5 | /// - [`assert_impl_all!`] 6 | /// - [`assert_impl_not_all!`] 7 | /// - [`assert_impl_not_any!`] 8 | /// 9 | /// # Examples 10 | /// 11 | /// Given some type `Foo`, it is expected to implement either `Snap`, `Crackle`, 12 | /// or `Pop`: 13 | /// 14 | /// ```compile_fail 15 | /// # use static_assertions::assert_impl_one; fn main() {} 16 | /// struct Foo; 17 | /// 18 | /// trait Snap {} 19 | /// trait Crackle {} 20 | /// trait Pop {} 21 | /// 22 | /// assert_impl_one!(Foo: Snap, Crackle, Pop); 23 | /// ``` 24 | /// 25 | /// If _only_ `Crackle` is implemented, the assertion passes: 26 | /// 27 | /// ``` 28 | /// # use static_assertions::assert_impl_one; fn main() {} 29 | /// # struct Foo; 30 | /// # trait Snap {} 31 | /// # trait Crackle {} 32 | /// # trait Pop {} 33 | /// impl Crackle for Foo {} 34 | /// 35 | /// assert_impl_one!(Foo: Snap, Crackle, Pop); 36 | /// ``` 37 | /// 38 | /// If `Snap` or `Pop` is _also_ implemented, the assertion fails: 39 | /// 40 | /// ```compile_fail 41 | /// # use static_assertions::assert_impl_one; fn main() {} 42 | /// # struct Foo; 43 | /// # trait Snap {} 44 | /// # trait Crackle {} 45 | /// # trait Pop {} 46 | /// # impl Crackle for Foo {} 47 | /// impl Pop for Foo {} 48 | /// 49 | /// assert_impl_one!(Foo: Snap, Crackle, Pop); 50 | /// ``` 51 | /// 52 | /// [`assert_impl_any!`]: macro.assert_impl_any.html 53 | /// [`assert_impl_all!`]: macro.assert_impl_all.html 54 | /// [`assert_impl_not_all!`]: macro.assert_not_impl_all.html 55 | /// [`assert_impl_not_any!`]: macro.assert_not_impl_any.html 56 | #[macro_export] 57 | macro_rules! assert_impl_one { 58 | ($x:ty: $($t:path),+ $(,)?) => { 59 | const _: fn() = || { 60 | // Generic trait that must be implemented for `$x` exactly once. 61 | trait AmbiguousIfMoreThanOne { 62 | // Required for actually being able to reference the trait. 63 | fn some_item() {} 64 | } 65 | 66 | // Creates multiple scoped `Token` types for each trait `$t`, over 67 | // which a specialized `AmbiguousIfMoreThanOne` is 68 | // implemented for every type that implements `$t`. 69 | $({ 70 | #[allow(dead_code)] 71 | struct Token; 72 | 73 | impl AmbiguousIfMoreThanOne for T {} 74 | })+ 75 | 76 | // If there is only one specialized trait impl, type inference with 77 | // `_` can be resolved and this can compile. Fails to compile if 78 | // `$x` implements more than one `AmbiguousIfMoreThanOne` or 79 | // does not implement any at all. 80 | let _ = <$x as AmbiguousIfMoreThanOne<_>>::some_item; 81 | }; 82 | }; 83 | } 84 | 85 | /// Asserts that the type implements _all_ of the given traits. 86 | /// 87 | /// See [`assert_impl_not_all!`] for achieving the opposite effect. 88 | /// 89 | /// # Examples 90 | /// 91 | /// This can be used to ensure types implement auto traits such as [`Send`] and 92 | /// [`Sync`], as well as traits with [blanket `impl`s][blanket]. 93 | /// 94 | /// ``` 95 | /// # #[macro_use] extern crate static_assertions; fn main() {} 96 | /// assert_impl_all!(u32: Copy, Send); 97 | /// assert_impl_all!(&str: Into); 98 | /// ``` 99 | /// 100 | /// The following example fails to compile because raw pointers do not implement 101 | /// [`Send`] since they cannot be moved between threads safely: 102 | /// 103 | /// ```compile_fail 104 | /// # #[macro_use] extern crate static_assertions; fn main() {} 105 | /// assert_impl_all!(*const u8: Send); 106 | /// ``` 107 | /// 108 | /// [`assert_impl_not_all!`]: macro.assert_not_impl_all.html 109 | /// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html 110 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 111 | /// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods 112 | #[macro_export(local_inner_macros)] 113 | macro_rules! assert_impl_all { 114 | ($ty:ty: $($traits:path),+ $(,)?) => { 115 | assert_impl!($ty: $( ($traits) )&+); 116 | }; 117 | } 118 | 119 | /// Asserts that the type implements _any_ of the given traits. 120 | /// 121 | /// See [`assert_impl_not_any!`] for achieving the opposite effect. 122 | /// 123 | /// # Examples 124 | /// 125 | /// `u8` cannot be converted from `u16`, but it can be converted into `u16`: 126 | /// 127 | /// ``` 128 | /// # #[macro_use] extern crate static_assertions; fn main() {} 129 | /// assert_impl_any!(u8: From, Into); 130 | /// ``` 131 | /// 132 | /// The unit type cannot be converted from `u8` or `u16`, but it does implement 133 | /// [`Send`]: 134 | /// 135 | /// ``` 136 | /// # #[macro_use] extern crate static_assertions; fn main() {} 137 | /// assert_impl_any!((): From, From, Send); 138 | /// ``` 139 | /// 140 | /// The following example fails to compile because raw pointers do not implement 141 | /// [`Send`] or [`Sync`] since they cannot be moved or shared between threads 142 | /// safely: 143 | /// 144 | /// ```compile_fail 145 | /// # #[macro_use] extern crate static_assertions; fn main() {} 146 | /// assert_impl_any!(*const u8: Send, Sync); 147 | /// ``` 148 | /// 149 | /// [`assert_impl_not_any!`]: macro.assert_not_impl_any.html 150 | /// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html 151 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 152 | #[macro_export(local_inner_macros)] 153 | macro_rules! assert_impl_any { 154 | ($ty:ty: $($traits:path),+ $(,)?) => { 155 | assert_impl!($ty: $( ($traits) )|+); 156 | }; 157 | } 158 | 159 | /// Asserts that the type does **not** implement _all_ of the given traits. 160 | /// 161 | /// This can be used to ensure types do not implement auto traits such as 162 | /// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket]. 163 | /// 164 | /// Note that the combination of all provided traits is required to not be 165 | /// implemented. If you want to check that none of multiple traits are 166 | /// implemented you should invoke [`assert_impl_not_any!`] instead. 167 | /// 168 | /// # Examples 169 | /// 170 | /// Although `u32` implements `From`, it does not implement `Into`: 171 | /// 172 | /// ``` 173 | /// # #[macro_use] extern crate static_assertions; fn main() {} 174 | /// assert_impl_not_all!(u32: From, Into); 175 | /// ``` 176 | /// 177 | /// The following example fails to compile since `u32` can be converted into 178 | /// `u64`. 179 | /// 180 | /// ```compile_fail 181 | /// # #[macro_use] extern crate static_assertions; fn main() {} 182 | /// assert_impl_not_all!(u32: Into); 183 | /// ``` 184 | /// 185 | /// The following compiles because [`Cell`] is not both [`Sync`] _and_ [`Send`]: 186 | /// 187 | /// ``` 188 | /// # #[macro_use] extern crate static_assertions; fn main() {} 189 | /// use std::cell::Cell; 190 | /// 191 | /// assert_impl_not_all!(Cell: Sync, Send); 192 | /// ``` 193 | /// 194 | /// But it is [`Send`], so this fails to compile: 195 | /// 196 | /// ```compile_fail 197 | /// # #[macro_use] extern crate static_assertions; fn main() {} 198 | /// # std::cell::Cell; 199 | /// assert_impl_not_all!(Cell: Send); 200 | /// ``` 201 | /// 202 | /// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html 203 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 204 | /// [`assert_impl_not_any!`]: macro.assert_impl_not_any.html 205 | /// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html 206 | /// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods 207 | #[macro_export(local_inner_macros)] 208 | macro_rules! assert_impl_not_all { 209 | ($ty:ty: $($traits:path),+ $(,)?) => { 210 | assert_impl!($ty: !( $( ($traits) )&+ )); 211 | }; 212 | } 213 | 214 | /// Asserts that the type does **not** implement _all_ of the given traits. 215 | /// 216 | /// This macro has been deprecated in favor of 217 | /// [`assert_impl_not_all!`](macro.assert_impl_not_all.html). 218 | #[deprecated( 219 | since = "1.2.0", 220 | note = "Please use the 'assert_impl_not_all' macro instead" 221 | )] 222 | #[macro_export(local_inner_macros)] 223 | macro_rules! assert_not_impl_all { 224 | ($($t:tt)*) => { 225 | assert_impl_not_all!($($t)*); 226 | }; 227 | } 228 | 229 | /// Asserts that the type does **not** implement _any_ of the given traits. 230 | /// 231 | /// This can be used to ensure types do not implement auto traits such as 232 | /// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket]. 233 | /// 234 | /// This macro causes a compilation failure if any of the provided individual 235 | /// traits are implemented for the type. If you want to check that a combination 236 | /// of traits is not implemented you should invoke [`assert_impl_not_all!`] 237 | /// instead. For single traits both macros behave the same. 238 | /// 239 | /// # Examples 240 | /// 241 | /// If `u32` were to implement `Into` conversions for `usize` _and_ for `u8`, 242 | /// the following would fail to compile: 243 | /// 244 | /// ``` 245 | /// # #[macro_use] extern crate static_assertions; fn main() {} 246 | /// assert_impl_not_any!(u32: Into, Into); 247 | /// ``` 248 | /// 249 | /// This is also good for simple one-off cases: 250 | /// 251 | /// ``` 252 | /// # #[macro_use] extern crate static_assertions; fn main() {} 253 | /// assert_impl_not_any!(&'static mut u8: Copy); 254 | /// ``` 255 | /// 256 | /// The following example fails to compile since `u32` can be converted into 257 | /// `u64` even though it can not be converted into a `u16`: 258 | /// 259 | /// ```compile_fail 260 | /// # #[macro_use] extern crate static_assertions; fn main() {} 261 | /// assert_impl_not_any!(u32: Into, Into); 262 | /// ``` 263 | /// 264 | /// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html 265 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 266 | /// [`assert_impl_not_all!`]: macro.assert_impl_not_all.html 267 | /// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods 268 | #[macro_export(local_inner_macros)] 269 | macro_rules! assert_impl_not_any { 270 | ($ty:ty: $($traits:path),+ $(,)?) => { 271 | assert_impl!($ty: !( $( ($traits) )|+ )); 272 | }; 273 | } 274 | 275 | /// Asserts that the type does **not** implement _any_ of the given traits. 276 | /// 277 | /// This macro has been deprecated in favor of 278 | /// [`assert_impl_not_any!`](macro.assert_impl_not_any.html). 279 | #[deprecated( 280 | since = "1.2.0", 281 | note = "Please use the 'assert_impl_not_any' macro instead" 282 | )] 283 | #[macro_export(local_inner_macros)] 284 | macro_rules! assert_not_impl_any { 285 | ($($t:tt)*) => { 286 | assert_impl_not_any!($($t)*); 287 | }; 288 | } 289 | 290 | /// Asserts that the type implements a logical trait expression. 291 | /// 292 | /// This macro causes a compilation failure if the expression is not satisfied. 293 | /// 294 | /// See [`does_impl!`](macro.does_impl.html) for simply getting a [`bool`] from 295 | /// this condition without asserting it. 296 | /// 297 | /// # Syntax 298 | /// 299 | /// ```skip 300 | /// assert_impl!(: ); 301 | /// assert_impl!(for(: ) : ); 302 | /// ``` 303 | /// 304 | /// where: 305 | /// 306 | /// - `` is a type (that must not depend on a generic parameter) 307 | /// 308 | /// - `` is an expression made out of trait names, combined with `!` 309 | /// for negation, `&` for conjunction, `|` for disjunction and parentheses for 310 | /// grouping. 311 | /// 312 | /// - `` is a trait bounds expression. 313 | /// 314 | /// For technical reasons: 315 | /// 316 | /// - Traits (like `Into`) that are not a single identifier must be 317 | /// surrounded by parentheses. 318 | /// 319 | /// - The usual operator priority is not respected: `x & y | z` is parsed as 320 | /// `x & (y | z)`. 321 | /// 322 | /// # Examples 323 | /// 324 | /// If `u32` were to implement `Into` conversions for `usize` _and_ for `u8`, 325 | /// the following would fail to compile: 326 | /// 327 | /// ``` 328 | /// # #[macro_use] extern crate static_assertions; fn main() {} 329 | /// assert_impl!(u32: !((Into) & (Into))); 330 | /// ``` 331 | /// 332 | /// Check that a type is [`Send`] but not [`Sync`]. 333 | /// 334 | /// ``` 335 | /// # #[macro_use] extern crate static_assertions; fn main() {} 336 | /// use std::cell::Cell; 337 | /// 338 | /// assert_impl!(Cell: Send & !Sync); 339 | /// ``` 340 | /// 341 | /// Check simple one-off cases: 342 | /// 343 | /// ``` 344 | /// # #[macro_use] extern crate static_assertions; fn main() {} 345 | /// assert_impl!(&'static mut u8: !Copy); 346 | /// ``` 347 | /// 348 | /// Check that a type is _always_ [`Clone`] even when its parameter isn't: 349 | /// 350 | /// ``` 351 | /// # #[macro_use] extern crate static_assertions; fn main() {} 352 | /// use std::rc::Rc; 353 | /// 354 | /// assert_impl!(for(T) Rc: Clone); 355 | /// ``` 356 | /// 357 | /// The following example fails to compile since `u64` cannot be converted into 358 | /// either `u32` or `u16`: 359 | /// 360 | /// ```compile_fail 361 | /// # #[macro_use] extern crate static_assertions; fn main() {} 362 | /// assert_impl!(u64: (Into) | (Into)); 363 | /// ``` 364 | /// 365 | /// [`bool`]: https://doc.rust-lang.org/std/primitive.bool.html 366 | /// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html 367 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 368 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 369 | #[macro_export(local_inner_macros)] 370 | macro_rules! assert_impl { 371 | (for($($generic:tt)*) $ty:ty: $($rest:tt)*) => { 372 | const _: () = { 373 | fn assert_impl<$($generic)*>() { 374 | // Construct an expression using `True`/`False` and their 375 | // operators, that corresponds to the provided expression. 376 | let _: $crate::True = $crate::_does_impl!($ty: $($rest)*); 377 | } 378 | }; 379 | }; 380 | ($ty:ty: $($rest:tt)*) => { 381 | // Construct an expression using `True`/`False` and their operators, 382 | // that corresponds to the provided expression. 383 | const _: $crate::True = $crate::_does_impl!($ty: $($rest)*); 384 | }; 385 | } 386 | -------------------------------------------------------------------------------- /src/assert_obj_safe.rs: -------------------------------------------------------------------------------- 1 | // FIXME: Link below is required to render in index 2 | /// Asserts that the traits support dynamic dispatch 3 | /// ([object-safety](https://doc.rust-lang.org/book/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects)). 4 | /// 5 | /// This is useful for when changes are made to a trait that accidentally 6 | /// prevent it from being used as an [object]. Such a case would be adding a 7 | /// generic method and forgetting to add `where Self: Sized` after it. If left 8 | /// unnoticed, that mistake will affect crate users and break both forward and 9 | /// backward compatibility. 10 | /// 11 | /// # Examples 12 | /// 13 | /// When exposing a public API, it's important that traits that could previously 14 | /// use dynamic dispatch can still do so in future compatible crate versions. 15 | /// 16 | /// ``` 17 | /// # #[macro_use] extern crate static_assertions; fn main() {} 18 | /// trait MySafeTrait { 19 | /// fn foo(&self) -> u32; 20 | /// } 21 | /// 22 | /// assert_obj_safe!(std::fmt::Write, MySafeTrait); 23 | /// ``` 24 | /// 25 | /// Works with traits that are not in the calling module: 26 | /// 27 | /// ``` 28 | /// # #[macro_use] extern crate static_assertions; fn main() {} 29 | /// mod inner { 30 | /// pub trait BasicTrait { 31 | /// fn bar(&self); 32 | /// } 33 | /// assert_obj_safe!(BasicTrait); 34 | /// } 35 | /// 36 | /// assert_obj_safe!(inner::BasicTrait); 37 | /// ``` 38 | /// 39 | /// The following example fails to compile because raw pointers cannot be sent 40 | /// between threads safely: 41 | /// 42 | /// ```compile_fail 43 | /// # #[macro_use] extern crate static_assertions; fn main() {} 44 | /// assert_impl!(*const u8, Send); 45 | /// ``` 46 | /// 47 | /// The following example fails to compile because generics without 48 | /// `where Self: Sized` are not allowed in [object-safe][object] trait methods: 49 | /// 50 | /// ```compile_fail 51 | /// # #[macro_use] extern crate static_assertions; fn main() {} 52 | /// trait MyUnsafeTrait { 53 | /// fn baz(&self) -> T; 54 | /// } 55 | /// 56 | /// assert_obj_safe!(MyUnsafeTrait); 57 | /// ``` 58 | /// 59 | /// When we fix that, the previous code will compile: 60 | /// 61 | /// ``` 62 | /// # #[macro_use] extern crate static_assertions; fn main() {} 63 | /// trait MyUnsafeTrait { 64 | /// fn baz(&self) -> T where Self: Sized; 65 | /// } 66 | /// 67 | /// assert_obj_safe!(MyUnsafeTrait); 68 | /// ``` 69 | /// 70 | /// [object]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects 71 | #[macro_export] 72 | macro_rules! assert_obj_safe { 73 | ($($xs:path),+ $(,)?) => { 74 | $(const _: Option<&$xs> = None;)+ 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /src/assert_size.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that types are equal in size. 2 | /// 3 | /// When performing operations such as pointer casts or dealing with [`usize`] 4 | /// versus [`u64`] versus [`u32`], the size of your types matter. That is where 5 | /// this macro comes into play. 6 | /// 7 | /// # Alternatives 8 | /// 9 | /// There also exists [`assert_size_eq_val`](macro.assert_size_eq_val.html) and 10 | /// [`assert_size_eq_ptr`](macro.assert_size_eq_ptr.html). Instead of specifying 11 | /// types to compare, values' sizes can be directly compared against each other. 12 | /// 13 | /// # Examples 14 | /// 15 | /// These three types, despite being very different, all have the same size: 16 | /// 17 | /// ``` 18 | /// # #[macro_use] extern crate static_assertions; fn main() {} 19 | /// assert_size_eq!([u8; 4], (u16, u16), u32); 20 | /// ``` 21 | /// 22 | /// The following example fails to compile because `u32` has 4 times the size of 23 | /// `u8`: 24 | /// 25 | /// ```compile_fail 26 | /// # #[macro_use] extern crate static_assertions; fn main() {} 27 | /// assert_size_eq!(u32, u8); 28 | /// ``` 29 | /// 30 | /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html 31 | /// [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html 32 | /// [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html 33 | #[macro_export] 34 | macro_rules! assert_size_eq { 35 | ($x:ty, $($xs:ty),+ $(,)?) => { 36 | const _: fn() = || { 37 | $(let _ = $crate::_core::mem::transmute::<$x, $xs>;)+ 38 | }; 39 | }; 40 | } 41 | 42 | /// Asserts that types are equal in alignment. 43 | /// 44 | /// This macro has been deprecated in favor of 45 | /// [`assert_size_eq!`](macro.assert_size_eq.html). 46 | #[deprecated( 47 | since = "1.2.0", 48 | note = "Please use the 'assert_size_eq' macro instead" 49 | )] 50 | #[macro_export(local_inner_macros)] 51 | macro_rules! assert_eq_size { 52 | ($($t:tt)*) => { 53 | assert_size_eq!($($t)*); 54 | }; 55 | } 56 | 57 | /// Asserts that values pointed to are equal in size. 58 | /// 59 | /// # Examples 60 | /// 61 | /// This especially is useful for when coercing pointers between different types 62 | /// and ensuring the underlying values are the same size. 63 | /// 64 | /// ``` 65 | /// # #[macro_use] extern crate static_assertions; fn main() {} 66 | /// fn operation(x: &(u32, u32), y: &[u16; 4]) { 67 | /// assert_size_eq_ptr!(x, y); 68 | /// // ... 69 | /// } 70 | /// ``` 71 | /// 72 | /// The following example fails to compile because byte arrays of different 73 | /// lengths have different sizes: 74 | /// 75 | /// ```compile_fail 76 | /// # #[macro_use] extern crate static_assertions; 77 | /// # fn main() { 78 | /// static BYTES: &[u8; 4] = &[ 79 | /// /* ... */ 80 | /// # 0; 4 81 | /// ]; 82 | /// 83 | /// static TABLE: &[u8; 16] = &[ 84 | /// /* ... */ 85 | /// # 0; 16 86 | /// ]; 87 | /// 88 | /// assert_size_eq_ptr!(BYTES, TABLE); 89 | /// ``` 90 | #[macro_export] 91 | macro_rules! assert_size_eq_ptr { 92 | ($x:expr, $($xs:expr),+ $(,)?) => { 93 | #[allow(unknown_lints, unsafe_code, forget_copy, useless_transmute)] 94 | let _ = || unsafe { 95 | use $crate::_core::{mem, ptr}; 96 | let mut copy = ptr::read($x); 97 | $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+ 98 | mem::forget(copy); 99 | }; 100 | } 101 | } 102 | 103 | /// Asserts that values pointed to are equal in size. 104 | /// 105 | /// This macro has been deprecated in favor of 106 | /// [`assert_size_eq_ptr!`](macro.assert_size_eq_ptr.html). 107 | #[deprecated( 108 | since = "1.2.0", 109 | note = "Please use the 'assert_size_eq_ptr' macro instead" 110 | )] 111 | #[macro_export(local_inner_macros)] 112 | macro_rules! assert_eq_size_ptr { 113 | ($($t:tt)*) => { 114 | assert_size_eq_ptr!($($t)*); 115 | }; 116 | } 117 | 118 | /// Asserts that values are equal in size. 119 | /// 120 | /// This macro doesn't consume its arguments and thus works for 121 | /// non-[`Clone`]able values. 122 | /// 123 | /// # Examples 124 | /// 125 | /// ``` 126 | /// # #[macro_use] extern crate static_assertions; 127 | /// # fn main() { 128 | /// struct Byte(u8); 129 | /// 130 | /// let x = 10u8; 131 | /// let y = Byte(42); // Works for non-cloneable types 132 | /// 133 | /// assert_size_eq_val!(x, y); 134 | /// assert_size_eq_val!(x, y, 0u8); 135 | /// # } 136 | /// ``` 137 | /// 138 | /// Even though both values are 0, they are of types with different sizes: 139 | /// 140 | /// ```compile_fail 141 | /// # #[macro_use] extern crate static_assertions; 142 | /// # fn main() { 143 | /// assert_size_eq_val!(0u8, 0u32); 144 | /// # } 145 | /// ``` 146 | /// 147 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 148 | #[macro_export(local_inner_macros)] 149 | macro_rules! assert_size_eq_val { 150 | ($x:expr, $($xs:expr),+ $(,)?) => { 151 | assert_size_eq_ptr!(&$x, $(&$xs),+); 152 | } 153 | } 154 | 155 | /// Asserts that values pointed to are equal in size. 156 | /// 157 | /// This macro has been deprecated in favor of 158 | /// [`assert_size_eq_val!`](macro.assert_size_eq_val.html). 159 | #[deprecated( 160 | since = "1.2.0", 161 | note = "Please use the 'assert_size_eq_val' macro instead" 162 | )] 163 | #[macro_export(local_inner_macros)] 164 | macro_rules! assert_eq_size_val { 165 | ($($t:tt)*) => { 166 | assert_size_eq_val!($($t)*); 167 | }; 168 | } 169 | -------------------------------------------------------------------------------- /src/assert_trait.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that the trait is a child of all of the other traits. 2 | /// 3 | /// Related: 4 | /// - [`assert_trait_super_all!`] 5 | /// 6 | /// # Examples 7 | /// 8 | /// All types that implement [`Copy`] must implement [`Clone`]: 9 | /// 10 | /// ``` 11 | /// # #[macro_use] extern crate static_assertions; fn main() {} 12 | /// assert_trait_sub_all!(Copy: Clone); 13 | /// ``` 14 | /// 15 | /// All types that implement [`Ord`] must implement [`PartialEq`], [`Eq`], and 16 | /// [`PartialOrd`]: 17 | /// 18 | /// ``` 19 | /// # #[macro_use] extern crate static_assertions; fn main() {} 20 | /// assert_trait_sub_all!(Ord: PartialEq, Eq, PartialOrd); 21 | /// ``` 22 | /// 23 | /// The following example fails to compile because [`Eq`] is not required for 24 | /// [`PartialOrd`]: 25 | /// 26 | /// ```compile_fail 27 | /// # #[macro_use] extern crate static_assertions; fn main() {} 28 | /// assert_trait_sub_all!(PartialOrd: Eq); 29 | /// ``` 30 | /// 31 | /// [`assert_trait_super_all!`]: macro.assert_trait_super_all.html 32 | /// 33 | /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html 34 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 35 | /// [`Ord`]: https://doc.rust-lang.org/std/cmp/trait.Ord.html 36 | /// [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html 37 | /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html 38 | /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html 39 | #[macro_export(local_inner_macros)] 40 | macro_rules! assert_trait_sub_all { 41 | ($sub:path: $($super:path),+ $(,)?) => { 42 | assert_impl!(for(T: $sub) T: $( ($super) )&+); 43 | }; 44 | } 45 | 46 | /// Asserts that the trait is a parent of all of the other traits. 47 | /// 48 | /// Related: 49 | /// - [`assert_trait_sub_all!`] 50 | /// 51 | /// # Examples 52 | /// 53 | /// With this, traits `A` and `B` can both be tested to require [`Copy`] on a 54 | /// single line: 55 | /// 56 | /// ``` 57 | /// # use static_assertions::assert_trait_super_all; 58 | /// trait A: Copy {} 59 | /// trait B: Copy {} 60 | /// 61 | /// assert_trait_super_all!(Copy: A, B); 62 | /// ``` 63 | /// 64 | /// Otherwise, each sub-trait would require its own call to 65 | /// [`assert_trait_sub_all!`]: 66 | /// 67 | /// ``` 68 | /// # #[macro_use] extern crate static_assertions; fn main() {} 69 | /// # trait A: Copy {} 70 | /// # trait B: Copy {} 71 | /// assert_trait_sub_all!(A: Copy); 72 | /// assert_trait_sub_all!(B: Copy); 73 | /// ``` 74 | /// 75 | /// The following example fails to compile because trait `C` does not require 76 | /// [`Copy`]: 77 | /// 78 | /// ```compile_fail 79 | /// # use static_assertions::assert_trait_super_all; 80 | /// # trait A: Copy {} 81 | /// # trait B: Copy {} 82 | /// trait C {} 83 | /// 84 | /// assert_trait_super_all!(Copy: A, B, C); 85 | /// ``` 86 | /// 87 | /// [`assert_trait_sub_all!`]: macro.assert_trait_sub_all.html 88 | /// 89 | /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html 90 | #[macro_export(local_inner_macros)] 91 | macro_rules! assert_trait_super_all { 92 | ($super:path: $($sub:path),+ $(,)?) => { 93 | $(assert_trait_sub_all!($sub: $super);)+ 94 | }; 95 | } 96 | 97 | /// Asserts that the trait is a child of one or more of the other traits. 98 | /// 99 | /// Related: 100 | /// - [`assert_impl_any!`] 101 | /// 102 | /// # Examples 103 | /// 104 | /// All types that implement [`Copy`] must implement [`Clone`]: 105 | /// 106 | /// ``` 107 | /// # #[macro_use] extern crate static_assertions; fn main() {} 108 | /// assert_trait_sub_any!(Copy: Clone); 109 | /// ``` 110 | /// 111 | /// All types that implement [`Ord`] must implement [`Eq`], but don't have to implement [`Clone`]: 112 | /// 113 | /// ``` 114 | /// # #[macro_use] extern crate static_assertions; fn main() {} 115 | /// assert_trait_sub_any!(Ord: Eq, Clone); 116 | /// ``` 117 | /// 118 | /// The following example fails to compile because neither [`Eq`] nor [`Clone`] are required for 119 | /// [`PartialOrd`]: 120 | /// 121 | /// ```compile_fail 122 | /// # #[macro_use] extern crate static_assertions; fn main() {} 123 | /// assert_trait_sub_any!(PartialOrd: Eq, Clone); 124 | /// ``` 125 | /// 126 | /// [`assert_impl_any!`]: macro.assert_impl_any.html 127 | /// 128 | /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html 129 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 130 | /// [`Ord`]: https://doc.rust-lang.org/std/cmp/trait.Ord.html 131 | /// [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html 132 | /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html 133 | /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html 134 | #[macro_export(local_inner_macros)] 135 | macro_rules! assert_trait_sub_any { 136 | ($sub:path: $($super:path),+ $(,)?) => { 137 | assert_impl!(for(T: $sub) T: $( ($super) )|+); 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /src/assert_type.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that _all_ types in a list are equal to each other. 2 | /// 3 | /// # Examples 4 | /// 5 | /// Often times, type aliases are used to express usage semantics via naming. In 6 | /// some cases, the underlying type may differ based on platform. However, other 7 | /// types like [`c_float`] will always alias the same type. 8 | /// 9 | /// ``` 10 | /// # #[macro_use] extern crate static_assertions; fn main() {} 11 | /// use std::os::raw::c_float; 12 | /// 13 | /// assert_type_eq_all!(c_float, f32); 14 | /// ``` 15 | /// 16 | /// This macro can also be used to compare types that involve lifetimes! Just 17 | /// use `'static` in that case: 18 | /// 19 | /// ``` 20 | /// # #[macro_use] extern crate static_assertions; 21 | /// # fn main() { 22 | /// type Buf<'a> = &'a [u8]; 23 | /// 24 | /// assert_type_eq_all!(Buf<'static>, &'static [u8]); 25 | /// # } 26 | /// ``` 27 | /// 28 | /// The following example fails to compile because `String` and `str` do not 29 | /// refer to the same type: 30 | /// 31 | /// ```compile_fail 32 | /// # #[macro_use] extern crate static_assertions; fn main() {} 33 | /// assert_type_eq_all!(String, str); 34 | /// ``` 35 | /// 36 | /// This should also work the other way around, regardless of [`Deref`] 37 | /// implementations. 38 | /// 39 | /// ```compile_fail 40 | /// # #[macro_use] extern crate static_assertions; fn main() {} 41 | /// assert_type_eq_all!(str, String); 42 | /// ``` 43 | /// 44 | /// [`c_float`]: https://doc.rust-lang.org/std/os/raw/type.c_float.html 45 | /// [`Deref`]: https://doc.rust-lang.org/std/ops/trait.Deref.html 46 | #[macro_export] 47 | macro_rules! assert_type_eq_all { 48 | ($x:ty, $($xs:ty),+ $(,)*) => { 49 | const _: fn() = || { $({ 50 | trait TypeEq { 51 | type This: ?Sized; 52 | } 53 | 54 | impl TypeEq for T { 55 | type This = Self; 56 | } 57 | 58 | fn assert_type_eq_all() 59 | where 60 | T: ?Sized + TypeEq, 61 | U: ?Sized, 62 | {} 63 | 64 | assert_type_eq_all::<$x, $xs>(); 65 | })+ }; 66 | }; 67 | } 68 | 69 | /// Asserts that _all_ types are **not** equal to each other. 70 | /// 71 | /// # Examples 72 | /// 73 | /// Rust has all sorts of slices, but they represent different types of data: 74 | /// 75 | /// ``` 76 | /// # #[macro_use] extern crate static_assertions; fn main() {} 77 | /// assert_type_ne_all!([u8], [u16], str); 78 | /// ``` 79 | /// 80 | /// The following example fails to compile because [`c_uchar`] is a type alias 81 | /// for [`u8`]: 82 | /// 83 | /// ```compile_fail 84 | /// # #[macro_use] extern crate static_assertions; fn main() {} 85 | /// use std::os::raw::c_uchar; 86 | /// 87 | /// assert_type_ne_all!(c_uchar, u8, u32); 88 | /// ``` 89 | /// 90 | /// [`c_uchar`]: https://doc.rust-lang.org/std/os/raw/type.c_uchar.html 91 | /// [`u8`]: https://doc.rust-lang.org/std/primitive.u8.html 92 | #[macro_export] 93 | macro_rules! assert_type_ne_all { 94 | ($x:ty, $($y:ty),+ $(,)?) => { 95 | const _: fn() = || { 96 | trait MutuallyExclusive {} 97 | impl MutuallyExclusive for $x {} 98 | $(impl MutuallyExclusive for $y {})+ 99 | }; 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /src/bool.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Copy)] 2 | pub struct True; 3 | #[derive(Clone, Copy)] 4 | pub struct False; 5 | 6 | impl True { 7 | pub const fn not(&self) -> &'static False { 8 | &False 9 | } 10 | pub const fn and<'a, T>(&self, other: &'a T) -> &'a T { 11 | other 12 | } 13 | pub const fn or(&self, _: &T) -> &'static True { 14 | &True 15 | } 16 | pub const fn value(&self) -> bool { 17 | true 18 | } 19 | } 20 | 21 | impl False { 22 | pub const fn not(&self) -> &'static True { 23 | &True 24 | } 25 | pub const fn and(&self, _: &T) -> &'static False { 26 | &False 27 | } 28 | pub const fn or<'a, T>(&self, other: &'a T) -> &'a T { 29 | other 30 | } 31 | pub const fn value(&self) -> bool { 32 | false 33 | } 34 | } 35 | 36 | pub trait ToBool: Sized { 37 | type Bool: Sized; 38 | const TO_BOOL: Self::Bool; 39 | } 40 | 41 | impl ToBool for [(); 0] { 42 | type Bool = False; 43 | const TO_BOOL: Self::Bool = False; 44 | } 45 | 46 | impl ToBool for [(); 1] { 47 | type Bool = True; 48 | const TO_BOOL: Self::Bool = True; 49 | } 50 | 51 | /// Converts a `const bool` to a type-level boolean. 52 | #[doc(hidden)] 53 | #[macro_export] 54 | macro_rules! _to_bool { 55 | ($x:expr) => {{ 56 | const X: bool = $x; 57 | <[(); X as usize] as $crate::_bool::ToBool>::TO_BOOL 58 | }}; 59 | } 60 | -------------------------------------------------------------------------------- /src/const_assert.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that constant expressions evaluate to `true`. 2 | /// 3 | /// Constant expressions can be ensured to have certain properties via this 4 | /// macro If the expression evaluates to `false`, the file will fail to compile. 5 | /// This is synonymous to [`static_assert` in C++][static_assert]. 6 | /// 7 | /// # Alternatives 8 | /// 9 | /// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for 10 | /// validating whether a sequence of expressions are equal to one another. 11 | /// 12 | /// # Examples 13 | /// 14 | /// A common use case is to guarantee properties about a constant value that's 15 | /// generated via meta-programming. 16 | /// 17 | /// ``` 18 | /// # #[macro_use] extern crate static_assertions; fn main() {} 19 | /// const VALUE: i32 = // ... 20 | /// # 3; 21 | /// 22 | /// const_assert!(VALUE >= 2); 23 | /// ``` 24 | /// 25 | /// Inputs are type-checked as booleans: 26 | /// 27 | /// ```compile_fail 28 | /// # #[macro_use] extern crate static_assertions; fn main() {} 29 | /// const_assert!(!0); 30 | /// ``` 31 | /// 32 | /// Despite this being a macro, we see this produces a type error: 33 | /// 34 | /// ```txt 35 | /// | const_assert!(!0); 36 | /// | ^^ expected bool, found integral variable 37 | /// | 38 | /// = note: expected type `bool` 39 | /// found type `{integer}` 40 | /// ``` 41 | /// 42 | /// The following fails to compile because multiplying by 5 does not have an 43 | /// identity property: 44 | /// 45 | /// ```compile_fail 46 | /// # #[macro_use] extern crate static_assertions; fn main() {} 47 | /// const_assert!(5 * 5 == 5); 48 | /// ``` 49 | /// 50 | /// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert 51 | #[macro_export(local_inner_macros)] 52 | macro_rules! const_assert { 53 | ($x:expr $(,)?) => { 54 | const _: $crate::True = _to_bool!($x); 55 | }; 56 | } 57 | 58 | /// Asserts that constants are equal in value. 59 | /// 60 | /// Use [`const_assert_eq_usize!`](macro.const_assert_eq_usize.html) for better 61 | /// error messages when asserting 62 | /// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) equality. 63 | /// 64 | /// # Examples 65 | /// 66 | /// This works as a shorthand for `const_assert!(a == b)`: 67 | /// 68 | /// ``` 69 | /// # #[macro_use] extern crate static_assertions; fn main() {} 70 | /// const TWO: i32 = 2; 71 | /// 72 | /// const_assert_eq!(TWO * TWO, TWO + TWO); 73 | /// ``` 74 | /// 75 | /// Just because 2 × 2 = 2 + 2 doesn't mean it holds true for other numbers: 76 | /// 77 | /// ```compile_fail 78 | /// # #[macro_use] extern crate static_assertions; fn main() {} 79 | /// const_assert_eq!(4 + 4, 4 * 4); 80 | /// ``` 81 | #[macro_export(local_inner_macros)] 82 | macro_rules! const_assert_eq { 83 | ($x:expr, $($y:expr),+ $(,)?) => { 84 | const_assert!($($x == $y)&&+); 85 | }; 86 | } 87 | 88 | /// Asserts that constants of type 89 | /// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) are equal in 90 | /// value. 91 | /// 92 | /// This is equivalent to [`const_assert_eq!`](macro.const_assert_eq.html) but 93 | /// allows for inspecting the values in error messages. 94 | #[macro_export] 95 | macro_rules! const_assert_eq_usize { 96 | ($x:expr, $($y:expr),+ $(,)?) => { 97 | // Assigned instance must match the annotated type or else it will fail. 98 | $(const _: [(); $x] = [(); $y];)+ 99 | }; 100 | } 101 | 102 | /// Asserts that constants are **not** equal in value. 103 | /// 104 | /// # Examples 105 | /// 106 | /// This works as a shorthand for `const_assert!(a != b)`: 107 | /// 108 | /// ``` 109 | /// # #[macro_use] extern crate static_assertions; fn main() {} 110 | /// const NUM: usize = 32; 111 | /// 112 | /// const_assert_ne!(NUM * NUM, 64); 113 | /// ``` 114 | /// 115 | /// The following example fails to compile because 2 is magic and 2 × 2 = 2 + 2: 116 | /// 117 | /// ```compile_fail 118 | /// # #[macro_use] extern crate static_assertions; fn main() {} 119 | /// const_assert_ne!(2 + 2, 2 * 2); 120 | /// ``` 121 | #[macro_export(local_inner_macros)] 122 | macro_rules! const_assert_ne { 123 | ($x:expr, $($y:expr),+ $(,)?) => { 124 | const_assert!($($x != $y)&&+); 125 | }; 126 | } 127 | 128 | /// Asserts that constants are less than each other. 129 | #[macro_export(local_inner_macros)] 130 | macro_rules! const_assert_lt { 131 | ($x:expr, $($y:expr),+ $(,)?) => { 132 | const_assert_lt!(@build $x, $($y),+); 133 | }; 134 | (@build $x:expr) => {}; 135 | (@build $x:expr, $($y:expr),+) => { 136 | const_assert!($x < _head!($($y),+)); 137 | const_assert_lt!(@build $($y),+); 138 | }; 139 | } 140 | 141 | /// Asserts that constants are less than or equal to each other. 142 | #[macro_export(local_inner_macros)] 143 | macro_rules! const_assert_le { 144 | ($x:expr, $($y:expr),+ $(,)?) => { 145 | const_assert_le!(@build $x, $($y),+); 146 | }; 147 | (@build $x:expr) => {}; 148 | (@build $x:expr, $($y:expr),+) => { 149 | const_assert!($x <= _head!($($y),+)); 150 | const_assert_le!(@build $($y),+); 151 | }; 152 | } 153 | 154 | /// Asserts that constants are greater than each other. 155 | #[macro_export(local_inner_macros)] 156 | macro_rules! const_assert_gt { 157 | ($x:expr, $($y:expr),+ $(,)?) => { 158 | const_assert_gt!(@build $x, $($y),+); 159 | }; 160 | (@build $x:expr) => {}; 161 | (@build $x:expr, $($y:expr),+) => { 162 | const_assert!($x > _head!($($y),+)); 163 | const_assert_gt!(@build $($y),+); 164 | }; 165 | } 166 | 167 | /// Asserts that constants are less than or equal to each other. 168 | #[macro_export(local_inner_macros)] 169 | macro_rules! const_assert_ge { 170 | ($x:expr, $($y:expr),+ $(,)?) => { 171 | const_assert_ge!(@build $x, $($y),+); 172 | }; 173 | (@build $x:expr) => {}; 174 | (@build $x:expr, $($y:expr),+) => { 175 | const_assert!($x >= _head!($($y),+)); 176 | const_assert_ge!(@build $($y),+); 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /src/does_impl.rs: -------------------------------------------------------------------------------- 1 | /// Returns `true` if the type does implement a logical trait expression. 2 | /// 3 | /// # Examples 4 | /// 5 | /// One can mimic `assert_impl!` using this macro: 6 | /// 7 | /// ``` 8 | /// # #[macro_use] extern crate static_assertions; fn main() {} 9 | /// const CONDITION: bool = does_impl!(u32: From); 10 | /// 11 | /// const_assert!(CONDITION); 12 | /// ``` 13 | #[macro_export(local_inner_macros)] 14 | macro_rules! does_impl { 15 | ($ty:ty: $($trait_expr:tt)+) => { 16 | _does_impl!($ty: $($trait_expr)+).value() 17 | }; 18 | } 19 | 20 | /// Returns `True` or `False` depending on whether the given type implements the 21 | /// given trait boolean expression. Can be used in const contexts if it doesn't 22 | /// depend on outer generic parameters. 23 | /// 24 | /// This is the core of `assert_impl`. 25 | #[doc(hidden)] 26 | #[macro_export(local_inner_macros)] 27 | macro_rules! _does_impl { 28 | ($ty:ty: $($rest:tt)*) => {{ 29 | #[allow(unused_imports)] 30 | use $crate::{ 31 | _bool::{True, False}, 32 | _core::{marker::PhantomData, ops::Deref}, 33 | }; 34 | 35 | // Fallback trait that returns false if the type does not implement a 36 | // given trait. 37 | trait DoesntImpl { 38 | const DOES_IMPL: False = False; 39 | } 40 | impl DoesntImpl for T {} 41 | 42 | // Construct an expression using `True`/`False` and their operators, 43 | // that corresponds to the provided expression. 44 | *_does_impl!(@boolexpr($ty,) $($rest)*) 45 | }}; 46 | 47 | (@boolexpr($($args:tt)*) ($($expr:tt)*)) => { 48 | _does_impl!(@boolexpr($($args)*) $($expr)*) 49 | }; 50 | (@boolexpr($($args:tt)*) !($($expr:tt)*)) => { 51 | _does_impl!(@boolexpr($($args)*) $($expr)*).not() 52 | }; 53 | (@boolexpr($($args:tt)*) ($($left:tt)*) | $($right:tt)*) => {{ 54 | let left = _does_impl!(@boolexpr($($args)*) $($left)*); 55 | let right = _does_impl!(@boolexpr($($args)*) $($right)*); 56 | left.or(right) 57 | }}; 58 | (@boolexpr($($args:tt)*) ($($left:tt)*) & $($right:tt)*) => {{ 59 | let left = _does_impl!(@boolexpr($($args)*) $($left)*); 60 | let right = _does_impl!(@boolexpr($($args)*) $($right)*); 61 | left.and(right) 62 | }}; 63 | (@boolexpr($($args:tt)*) !($($left:tt)*) | $($right:tt)*) => {{ 64 | _does_impl!(@boolexpr($($args)*) (!($($left)*)) | $($right)*) 65 | }}; 66 | (@boolexpr($($args:tt)*) !($($left:tt)*) & $($right:tt)*) => {{ 67 | _does_impl!(@boolexpr($($args)*) (!($($left)*)) & $($right)*) 68 | }}; 69 | (@boolexpr($($args:tt)*) !$left:ident | $($right:tt)*) => {{ 70 | _does_impl!(@boolexpr($($args)*) !($left) | $($right)*) 71 | }}; 72 | (@boolexpr($($args:tt)*) !$left:ident & $($right:tt)*) => {{ 73 | _does_impl!(@boolexpr($($args)*) !($left) & $($right)*) 74 | }}; 75 | (@boolexpr($($args:tt)*) $left:ident | $($right:tt)*) => { 76 | _does_impl!(@boolexpr($($args)*) ($left) | $($right)*) 77 | }; 78 | (@boolexpr($($args:tt)*) $left:ident & $($right:tt)*) => {{ 79 | _does_impl!(@boolexpr($($args)*) ($left) & $($right)*) 80 | }}; 81 | (@boolexpr($($args:tt)*) !$expr:ident) => { 82 | _does_impl!(@boolexpr($($args)*) !($expr)) 83 | }; 84 | (@boolexpr($($args:tt)*) !$expr:path) => { 85 | _does_impl!(@boolexpr($($args)*) !($expr)) 86 | }; 87 | (@boolexpr($($args:tt)*) $expr:ident) => { 88 | _does_impl!(@base($($args)*) $expr) 89 | }; 90 | (@boolexpr($($args:tt)*) $expr:path) => { 91 | _does_impl!(@base($($args)*) $expr) 92 | }; 93 | 94 | (@base($ty:ty, $($args:tt)*) $($trait:tt)*) => {{ 95 | // Base case: computes whether `ty` implements `trait`. 96 | struct Wrapper(PhantomData); 97 | 98 | #[allow(dead_code)] 99 | impl Wrapper { 100 | const DOES_IMPL: True = True; 101 | } 102 | 103 | // If `$type: $trait`, the `_does_impl` inherent method on `Wrapper` 104 | // will be called, and return `True`. Otherwise, the trait method will 105 | // be called, which returns `False`. 106 | &>::DOES_IMPL 107 | }}; 108 | } 109 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs) 2 | //! 3 | //!
4 | //! 5 | //! Downloads 6 | //! 7 | //! 8 | //! Build Status 9 | //! 10 | //! rustc ^1.37.0 11 | //!

12 | //!
13 | //! 14 | //! Assertions to ensure correct assumptions about constants, types, and more. 15 | //! 16 | //! _All_ checks provided by this crate are performed at [compile-time]. This 17 | //! allows for finding errors quickly and early when it comes to ensuring 18 | //! certain features or aspects of a codebase. These macros are especially 19 | //! important when exposing a public API that requires types to be the same size 20 | //! or implement certain traits. 21 | //! 22 | //! # Usage 23 | //! 24 | //! This crate is available [on crates.io][crate] and can be used by adding the 25 | //! following to your project's [`Cargo.toml`]: 26 | //! 27 | //! ```toml 28 | //! [dependencies] 29 | //! static_assertions = "1.1.0" 30 | //! ``` 31 | //! 32 | //! and this to your crate root (`main.rs` or `lib.rs`): 33 | //! 34 | //! ``` 35 | //! # #[allow(unused_imports)] 36 | //! #[macro_use] 37 | //! extern crate static_assertions; 38 | //! # fn main() {} 39 | //! ``` 40 | //! 41 | //! When using [Rust 2018 edition][2018], the following shorthand can help if 42 | //! having `#[macro_use]` is undesirable. 43 | //! 44 | //! ```edition2018 45 | //! extern crate static_assertions as sa; 46 | //! 47 | //! sa::const_assert!(true); 48 | //! ``` 49 | //! 50 | //! ## Procedural Extensions 51 | //! 52 | //! As an extension crate [`proc_static_assertions`] adds a number of new 53 | //! assertions to this. These are implemented as [procedural macros], hence the 54 | //! "proc" prefix. As a result, they have a bit more visibility over what's 55 | //! being asserted over than normal macros would. 56 | //! 57 | //! It can be enabled via the `proc` feature flag in your [`Cargo.toml`]: 58 | //! 59 | //! ```toml 60 | //! [dependencies] 61 | //! static_assertions = { version = "1.1.0", features = ["proc"] } 62 | //! ``` 63 | //! 64 | //! # Examples 65 | //! 66 | //! Very thorough examples are provided in the docs for 67 | //! [each individual macro](#macros). Failure case examples are also documented. 68 | //! 69 | //! # Changes 70 | //! 71 | //! See [`CHANGELOG.md`](https://github.com/nvzqz/static-assertions-rs/blob/master/CHANGELOG.md) 72 | //! for an exhaustive list of what has changed from one version to another. 73 | //! 74 | //! # Donate 75 | //! 76 | //! This project is made freely available (as in free beer), but unfortunately 77 | //! not all beer is free! So, if you would like to buy me a beer (or coffee or 78 | //! *more*), then consider supporting my work that's benefited your project 79 | //! and thousands of others. 80 | //! 81 | //! 82 | //! Become a Patron! 83 | //! 84 | //! 85 | //! Buy me a coffee 86 | //! 87 | //! 88 | //! [`proc_static_assertions`]: https://docs.rs/proc_static_assertions 89 | //! [procedural macros]: https://doc.rust-lang.org/book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes 90 | //! [Rust 1.37]: https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html 91 | //! [2018]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#rust-2018 92 | //! [crate]: https://crates.io/crates/static_assertions 93 | //! [compile-time]: https://en.wikipedia.org/wiki/Compile_time 94 | //! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html 95 | 96 | #![deny(missing_docs, unused_macros)] 97 | #![doc( 98 | html_root_url = "https://docs.rs/static_assertions/1.1.0", 99 | html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png", 100 | test(attr(deny(warnings), allow(dead_code))) 101 | )] 102 | #![no_std] 103 | 104 | #[cfg(feature = "proc_static_assertions")] 105 | extern crate proc_static_assertions; 106 | #[cfg(feature = "proc_static_assertions")] 107 | pub use proc_static_assertions::assert; 108 | 109 | // This module should never be used publicly and is not part of this crate's 110 | // semver requirements. 111 | #[doc(hidden)] 112 | pub extern crate core as _core; 113 | 114 | mod assert_align; 115 | mod assert_cfg; 116 | mod assert_fields; 117 | mod assert_impl; 118 | mod assert_obj_safe; 119 | mod assert_size; 120 | mod assert_trait; 121 | mod assert_type; 122 | mod const_assert; 123 | mod does_impl; 124 | 125 | // Utility macros. 126 | // 127 | // These macros should also never be used publicly and are not part of this 128 | // crate's semver requirements. 129 | mod util; 130 | 131 | // Type-level booleans. 132 | // 133 | // This module should never be used publicly and is not part of this crate's 134 | // semver requirements. 135 | #[doc(hidden)] 136 | #[path = "bool.rs"] 137 | pub mod _bool; 138 | 139 | // These types should also never be used publicly and are not part of this 140 | // crate's semver requirements. 141 | #[doc(hidden)] 142 | pub use _bool::{False, True}; 143 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | #[doc(hidden)] 2 | #[macro_export] 3 | macro_rules! _head { 4 | ($head:expr $(, $tail:expr)* $(,)?) => { 5 | $head 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /tests/const.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | const_assert!(true && (true != false)); 8 | const_assert!((true && true) != false); 9 | const_assert_eq!(false, false); 10 | 11 | #[allow(dead_code)] 12 | const FIVE: usize = 5; 13 | 14 | const_assert!(FIVE * 2 == 10); 15 | const_assert!(FIVE > 2); 16 | -------------------------------------------------------------------------------- /tests/eq_size.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | assert_size_eq!(u8, u8, (u8,), [u8; 1]); 8 | 9 | mod assoc_type { 10 | trait Trait { 11 | type AssocItem: ?Sized; 12 | } 13 | 14 | impl Trait for T { 15 | type AssocItem = Self; 16 | } 17 | 18 | #[allow(dead_code)] 19 | struct Value; 20 | 21 | assert_size_eq!(::AssocItem, Value); 22 | 23 | // TODO: Is this possible? 24 | // pub fn test() { 25 | // assert_size_eq!(::AssocItem, T); 26 | // } 27 | } 28 | 29 | // Placed in separate module so that DropCounter's fields are private 30 | mod dc { 31 | /// A type that acts like somewhat of a reference counter. 32 | pub struct DropCounter<'a> { 33 | count: &'a mut i32, 34 | } 35 | 36 | impl<'a> DropCounter<'a> { 37 | pub fn new(count: &'a mut i32) -> DropCounter<'a> { 38 | *count += 1; 39 | DropCounter { count } 40 | } 41 | 42 | pub fn count(&self) -> i32 { 43 | *self.count 44 | } 45 | } 46 | 47 | impl<'a> Drop for DropCounter<'a> { 48 | fn drop(&mut self) { 49 | *self.count -= 1 50 | } 51 | } 52 | } 53 | use dc::*; 54 | 55 | /// A type that panics on drop. 56 | #[allow(dead_code)] 57 | struct PanicDrop(T); 58 | 59 | impl Drop for PanicDrop { 60 | fn drop(&mut self) { 61 | panic!("Dropped!"); 62 | } 63 | } 64 | 65 | #[test] 66 | fn test_eq_size() { 67 | assert_size_eq!([u8; 2], u16); 68 | assert_size_eq!([u8; 2], u16, (u8, u8)); 69 | assert_size_eq!([u8; 4], u32, (u16, u8, u8), (u16, u16)); 70 | 71 | assert_size_eq_val!([0u8; 2], 0u16); 72 | assert_size_eq_val!([0u8; 2], 0u16, (0u8, 0u8)); 73 | assert_size_eq_val!([0u8; 4], 0u32, (0u16, 0u8, 0u8), (0u16, 0u16)); 74 | 75 | #[deny(unused_unsafe)] 76 | { 77 | assert_size_eq!(u8, u8); 78 | assert_size_eq_val!(0u8, 0u8); 79 | } 80 | 81 | let x = &mut 0; 82 | assert_size_eq_ptr!(x, &0); 83 | *x = 20; 84 | assert_size_eq_ptr!(x, &0); 85 | 86 | // Should fail to compile (un-comment to test manually): 87 | // assert_size_eq!(u8, u16); 88 | // assert_size_eq_val!(0u8, 0u16); 89 | } 90 | 91 | #[test] 92 | fn test_eq_size_no_drop() { 93 | assert_size_eq!(u32, PanicDrop); 94 | assert_size_eq!(PanicDrop, u32); 95 | assert_size_eq!(PanicDrop, PanicDrop); 96 | } 97 | 98 | #[test] 99 | fn test_eq_size_drop_count() { 100 | let mut count = 0; 101 | { 102 | let dc = DropCounter::new(&mut count); 103 | assert_eq!(dc.count(), 1); 104 | assert_size_eq_val!(dc, 0usize); 105 | assert_eq!(dc.count(), 1); 106 | assert_size_eq_val!(dc, 0usize, dc); 107 | assert_eq!(dc.count(), 1); 108 | } 109 | assert_eq!(count, 0); 110 | 111 | assert_size_eq_val!(DropCounter::new(&mut count), 0usize); 112 | assert_eq!(count, 0); 113 | } 114 | -------------------------------------------------------------------------------- /tests/fields.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | #[allow(dead_code)] 8 | enum Foo { 9 | A { x: u8, y: u8 }, 10 | B(u8), 11 | } 12 | 13 | assert_fields!(Foo::A: x); 14 | assert_fields!(Foo::A: x, x); 15 | assert_fields!(Foo::A: x, y, x); 16 | 17 | // TODO: Make tuple field access possible 18 | // assert_fields!(Foo::B, 0); 19 | 20 | mod m { 21 | #[allow(dead_code)] 22 | pub struct Bar { 23 | pub nul: (), 24 | pub inner: T, 25 | } 26 | } 27 | 28 | #[allow(dead_code)] 29 | use m::Bar as Baz; 30 | 31 | assert_fields!(m::Bar: inner, nul); 32 | assert_fields!(Baz: inner, nul); 33 | -------------------------------------------------------------------------------- /tests/obj_safe.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | assert_obj_safe!(core::fmt::Debug, Send, Sync); 8 | 9 | trait ObjSafe {} 10 | assert_obj_safe!(ObjSafe); 11 | -------------------------------------------------------------------------------- /tests/proc_size.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "proc")] 2 | 3 | #[macro_use] 4 | extern crate static_assertions; 5 | 6 | #[assert(size == 4, align == 4)] 7 | struct Foo { 8 | value: i32, 9 | } 10 | -------------------------------------------------------------------------------- /tests/trait_impl.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | use core::ops::Range; 8 | 9 | trait Tri {} 10 | 11 | impl Tri for T {} 12 | 13 | assert_impl_all!( 14 | u64: Tri<[&'static u8], dyn Tri, (u16, u16)> 15 | ); 16 | assert_impl_all!(u8: Send, Sync); 17 | assert_impl_all!(&'static [u8]: IntoIterator); 18 | assert_impl_all!(Range: Iterator); 19 | assert_impl_all!([u8]: Send, Sync, AsRef<[u8]>); 20 | assert_impl_all!(str: Send, Sync, AsRef<[u8]>,); 21 | 22 | assert_impl_any!((): Send, Sync); 23 | assert_impl_any!((): Send, From); 24 | assert_impl_any!((): From, From, Send); 25 | 26 | #[allow(dead_code)] 27 | struct Foo; 28 | 29 | trait A {} 30 | trait B {} 31 | trait C {} 32 | 33 | impl B for Foo {} 34 | 35 | assert_impl_one!(Foo: A, B); 36 | assert_impl_one!(Foo: B, A); 37 | assert_impl_one!(Foo: B, C); 38 | assert_impl_one!(Foo: C, B); 39 | assert_impl_one!(Foo: A, B, C); 40 | assert_impl_one!(Foo: B, C, A); 41 | assert_impl_one!(Foo: C, A, B); 42 | 43 | #[derive(Clone)] 44 | struct Test; 45 | 46 | assert_impl!(u8: (From) | (Into)); 47 | assert_impl!((): (From) | (From) | Send); 48 | assert_impl!((): (!From) & !(From) & Send); 49 | assert_impl!((): Copy | Clone); 50 | assert_impl!((): Copy & Clone); 51 | assert_impl!(Test: Copy | Clone); 52 | assert_impl!(Test: !Copy | Clone); 53 | assert_impl!(Test: !Copy & Clone); 54 | assert_impl!(Test: !Copy & (Clone)); 55 | assert_impl!(Test: !(Copy) & Clone); 56 | assert_impl!(Test: !(!Clone)); 57 | assert_impl!(Test: !(Copy) & !(!Clone)); 58 | assert_impl!(Test: !(Copy & Clone)); 59 | assert_impl!(str: !Copy & !Clone); 60 | 61 | #[derive(Clone)] 62 | struct Box(T); 63 | 64 | assert_impl!(for(T: Clone) Box: Clone); 65 | assert_impl!(for(T: Clone + Send) Box: Clone & Send); 66 | assert_impl!(for(T) Box: (From) & (Into)); 67 | 68 | assert_impl!(for(T) PhantomData: Clone); 69 | assert_impl!(for(T: Copy) T: Clone); 70 | assert_impl!(for(T: ?Sized) T: Clone | !Clone); 71 | assert_impl!(for('a, T: 'a) &'a mut T: !Copy); 72 | -------------------------------------------------------------------------------- /tests/type_eq.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | assert_type_eq_all!([u8], [u8]); 8 | 9 | #[allow(dead_code)] 10 | type X = u8; 11 | 12 | #[allow(unused_parens)] 13 | mod m { 14 | assert_type_eq_all!(super::X, u8, (super::X)); 15 | } 16 | -------------------------------------------------------------------------------- /tests/type_ne.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unsafe_code)] 3 | 4 | #[macro_use] 5 | extern crate static_assertions; 6 | 7 | assert_type_ne_all!(u8, u16, u32); 8 | --------------------------------------------------------------------------------