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}