const_macros/lib.rs
1//! Various macros for const contexts.
2//!
3//! # Examples
4//!
5//! Below is an example that utilizes most of the macros provided by this crate.
6//!
7//! ```
8//! use const_macros::{const_assert, const_early, const_ok, const_try};
9//!
10//! use thiserror::Error;
11//!
12//! #[derive(Error, Debug)]
13//! #[error("unexpected length: `{value}`")]
14//! pub struct Error {
15//! pub value: usize,
16//! }
17//!
18//! impl Error {
19//! pub const fn new(value: usize) -> Self {
20//! Self { value }
21//! }
22//! }
23//!
24//! pub const MIN: usize = 32;
25//! pub const MAX: usize = 96;
26//!
27//! const_assert!(MIN <= MAX);
28//!
29//! #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30//! pub struct Length {
31//! value: usize,
32//! }
33//!
34//! impl Length {
35//! pub const fn new(value: usize) -> Result<Self, Error> {
36//! const_try!(Self::check(value));
37//!
38//! Ok(unsafe { Self::new_unchecked(value) })
39//! }
40//!
41//! pub const fn new_ok(value: usize) -> Option<Self> {
42//! const_ok!(Self::new(value))
43//! }
44//!
45//! pub const fn check(value: usize) -> Result<(), Error> {
46//! const_early!(value < MIN || value > MAX => Error::new(value));
47//!
48//! Ok(())
49//! }
50//!
51//! pub const unsafe fn new_unchecked(value: usize) -> Self {
52//! Self { value }
53//! }
54//!
55//! pub const MIN: Self = Self::new_ok(MIN).unwrap();
56//! pub const MAX: Self = Self::new_ok(MAX).unwrap();
57//! }
58//! ```
59
60#![no_std]
61#![deny(missing_docs)]
62
63#[allow(unused_imports)]
64#[doc(hidden)]
65pub mod import {
66 pub use core::{option::Option, result::Result};
67}
68
69/// Similar to the `?` operator used on [`Result`] but for `const` contexts.
70///
71/// Note that no conversions are performed, as it is impossible in `const` contexts.
72#[macro_export]
73macro_rules! const_try {
74 ($result: expr) => {
75 match $result {
76 $crate::import::Result::Ok(value) => value,
77 $crate::import::Result::Err(error) => return $crate::import::Result::Err(error),
78 }
79 };
80}
81
82/// Equivalent to the `?` operator used on [`Option`] but for `const` contexts.
83#[macro_export]
84macro_rules! const_none {
85 ($option: expr) => {
86 match $option {
87 $crate::import::Option::Some(value) => value,
88 $crate::import::Option::None => return $crate::import::Option::None,
89 }
90 };
91}
92
93/// Same as [`Option::map`] but for `const` contexts.
94#[macro_export]
95macro_rules! const_map {
96 ($option: expr => $function: expr) => {
97 match $option {
98 $crate::import::Option::Some(value) => $crate::import::Option::Some($function(value)),
99 $crate::import::Option::None => $crate::import::Option::None,
100 }
101 };
102}
103
104/// Same as [`Result::ok`] but for `const` contexts.
105#[macro_export]
106macro_rules! const_ok {
107 ($result: expr) => {
108 match $result {
109 $crate::import::Result::Ok(value) => $crate::import::Option::Some(value),
110 $crate::import::Result::Err(_) => $crate::import::Option::None,
111 }
112 };
113}
114
115/// Same as [`Result::err`] but for `const` contexts.
116#[macro_export]
117macro_rules! const_err {
118 ($result: expr) => {
119 match $result {
120 $crate::import::Result::Ok(_) => $crate::import::Option::None,
121 $crate::import::Result::Err(error) => $crate::import::Option::Some(error),
122 }
123 };
124}
125
126/// Same as [`Result::map`] but for `const` contexts.
127#[macro_export]
128macro_rules! const_map_ok {
129 ($result: expr => $function: expr) => {
130 match $result {
131 $crate::import::Result::Ok(value) => $crate::import::Result::Ok($function(value)),
132 $crate::import::Result::Err(error) => $crate::import::Result::Err(error),
133 }
134 };
135}
136
137/// Same as [`Result::map_err`] but for `const` contexts.
138#[macro_export]
139macro_rules! const_map_err {
140 ($result: expr => $function: expr) => {
141 match $result {
142 $crate::import::Result::Ok(value) => $crate::import::Result::Ok(value),
143 $crate::import::Result::Err(error) => $crate::import::Result::Err($function(error)),
144 }
145 };
146}
147
148/// Returns early with the provided error if the condition is true.
149#[macro_export]
150macro_rules! const_early {
151 ($condition: expr => $error: expr) => {
152 if $condition {
153 return $crate::import::Result::Err($error);
154 }
155 };
156}
157
158/// Returns early with [`None`] if the condition is true.
159#[macro_export]
160macro_rules! const_quick {
161 ($condition: expr) => {
162 if $condition {
163 return $crate::import::Option::None;
164 }
165 };
166}
167
168/// Similar to [`assert!`] but for `const` contexts.
169#[macro_export]
170macro_rules! const_assert {
171 ($condition: expr) => {
172 const _: () = assert!($condition);
173 };
174}
175
176/// Similar to [`assert_eq!`] but for `const` contexts.
177#[macro_export]
178macro_rules! const_assert_eq {
179 ($left: expr, $right: expr $(,)?) => {
180 $crate::const_assert!($left == $right);
181 };
182}
183
184/// Similar to [`assert_ne!`] but for `const` contexts.
185#[macro_export]
186macro_rules! const_assert_ne {
187 ($left: expr, $right: expr $(,)?) => {
188 $crate::const_assert!($left != $right);
189 };
190}