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 [`Result::ok`] but for `const` contexts.
94#[macro_export]
95macro_rules! const_ok {
96 ($result: expr) => {
97 match $result {
98 $crate::import::Result::Ok(value) => $crate::import::Option::Some(value),
99 $crate::import::Result::Err(_) => $crate::import::Option::None,
100 }
101 };
102}
103
104/// Same as [`Result::err`] but for `const` contexts.
105#[macro_export]
106macro_rules! const_err {
107 ($result: expr) => {
108 match $result {
109 $crate::import::Result::Ok(_) => $crate::import::Option::None,
110 $crate::import::Result::Err(error) => $crate::import::Option::Some(error),
111 }
112 };
113}
114
115/// Returns early with the provided error if the condition is true.
116#[macro_export]
117macro_rules! const_early {
118 ($condition: expr => $error: expr) => {
119 if $condition {
120 return $crate::import::Result::Err($error);
121 }
122 };
123}
124
125/// Similar to [`assert!`] but for `const` contexts.
126#[macro_export]
127macro_rules! const_assert {
128 ($condition: expr) => {
129 const _: () = assert!($condition);
130 };
131}
132
133/// Similar to [`assert_eq!`] but for `const` contexts.
134#[macro_export]
135macro_rules! const_assert_eq {
136 ($left: expr, $right: expr, $(,)?) => {
137 $crate::const_assert!($left == $right);
138 };
139}
140
141/// Similar to [`assert_ne!`] but for `const` contexts.
142#[macro_export]
143macro_rules! const_assert_ne {
144 ($left: expr, $right: expr, $(,)?) => {
145 $crate::const_assert!($left != $right);
146 };
147}