├── .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 | [](https://github.com/nvzqz/static-assertions-rs)
2 |
3 |
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 | //! [](https://github.com/nvzqz/static-assertions-rs)
2 | //!
3 | //!
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 | //!
66 | //!
67 | //!
68 | //!
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 | //! [](https://github.com/nvzqz/static-assertions-rs)
2 | //!
3 | //!
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 | //!
83 | //!
84 | //!
85 | //!
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 |
--------------------------------------------------------------------------------