const_ft/
lib.rs

1#![cfg_attr(feature = "const_fn", feature(const_fn))]
2#![no_std]
3
4//! A macro for easy generation and wrapping of a const function under a const_fn feature gate.
5//!
6//! The macro will generate two functions with the same name - one const fn for when the feature gate
7//! `const_fn` is enabled and the other for the all other cases.
8//!
9//! `const` fns are unstable, and the const_fn feature gate should be enabled only on nightly.
10//!
11//! The macro accepts a single function block, as an input. To include multiple functions, you have
12//! to use separate macro calls. The macro works for public, private and pub(x) functions.
13//!
14//! To install this crate as a dependency, add it to your Cargo.toml:
15//!
16//! ```toml
17//! const_ft = { version =  "0.1", features = "const_fn" }
18//! ```
19//!
20//! Example:
21//!
22//! ```rust
23//! #![cfg_attr(feature = "const_fn", feature(const_fn))]
24//!
25//! #[macro_use]
26//! extern crate const_ft;
27//!
28//! const_ft! {
29//!      pub fn some_function() -> u32 {
30//!         1u32
31//!      }
32//! }
33//!
34//!
35//! fn main() {
36//!     assert_eq!(some_function(), 1u32);
37//! }
38//! ```
39//!
40
41#[macro_export]
42macro_rules! const_ft {
43    (pub fn $fn_name:ident($($arg:ident : $typ:ty),*) $body: block ) => {
44        #[cfg(feature = "const_fn")]
45        pub const fn $fn_name($($arg : $typ,)*) $body
46
47        #[cfg(not(feature = "const_fn"))]
48        pub fn $fn_name($($arg : $typ,)*) $body
49    };
50    (pub fn $fn_name:ident($($arg:ident : $typ:ty),*) -> $ret: ty $body: block ) => {
51        #[cfg(feature = "const_fn")]
52        pub const fn $fn_name($($arg : $typ,)*) -> $ret $body
53
54        #[cfg(not(feature = "const_fn"))]
55        pub fn $fn_name($($arg : $typ,)*) -> $ret $body
56    };
57
58    (fn $fn_name:ident($($arg:ident : $typ:ty),*) -> $ret: ty $body: block ) => {
59        #[cfg(feature = "const_fn")]
60        const fn $fn_name($($arg : $typ,)*) -> $ret $body
61
62        #[cfg(not(feature = "const_fn"))]
63        fn $fn_name($($arg : $typ,)*) -> $ret $body
64    };
65
66    (fn $fn_name:ident($($arg:ident : $typ:ty),*) $body: block ) => {
67        #[cfg(feature = "const_fn")]
68        const fn $fn_name($($arg : $typ,)*) $body
69
70        #[cfg(not(feature = "const_fn"))]
71        fn $fn_name($($arg : $typ,)*) $body
72    };
73
74    (pub($scope:ident) fn $fn_name:ident($($arg:ident : $typ:ty),*) -> $ret:ty $body:block ) => {
75        #[cfg(feature = "const_fn")]
76        pub($scope) const fn $fn_name($($arg : $typ,)*) -> $ret $body
77
78        #[cfg(not(feature = "const_fn"))]
79         pub($scope) fn $fn_name($($arg : $typ,)*) -> $ret $body
80    };
81
82    (pub($scope:ident) fn $fn_name:ident($($arg:ident : $typ:ty),*) $body:block ) => {
83        #[cfg(feature = "const_fn")]
84        pub($scope) const fn $fn_name($($arg : $typ,)*) $body
85
86        #[cfg(not(feature = "const_fn"))]
87        pub($scope) fn $fn_name($($arg : $typ,)*) $body
88    };
89
90    (fn $fn_name:ident( $self_:ident, $($arg:ident : $typ:ty),*) $body: block ) => {
91        #[cfg(feature = "const_fn")]
92        pub const fn $fn_name($self_:ident, $($arg : $typ,)*) $body
93
94        #[cfg(not(feature = "const_fn"))]
95        pub fn $fn_name($self_:ident, $($arg : $typ,)*) $body
96    };
97    (fn $fn_name:ident($self_:ident, $($arg:ident : $typ:ty),*) -> $ret: ty $body: block ) => {
98        #[cfg(feature = "const_fn")]
99        pub const fn $fn_name($self_, $($arg : $typ,)*) -> $ret $body
100
101        #[cfg(not(feature = "const_fn"))]
102        pub fn $fn_name($self_, $($arg : $typ,)*) -> $ret $body
103    };
104
105   (pub fn $fn_name:ident(&$self_: ident, $($arg:ident : $typ:ty),*) -> $ret: ty $body: block ) => {
106        #[cfg(feature = "const_fn")]
107        pub const fn $fn_name(&$self_, $($arg : $typ,)*) -> $ret $body
108
109        #[cfg(not(feature = "const_fn"))]
110        pub fn $fn_name(&$self_, $($arg : $typ,)*) -> $ret $body
111    };
112
113    (pub fn $fn_name:ident(&$self_: ident, $($arg:ident : $typ:ty),*) -> $body: block ) => {
114        #[cfg(feature = "const_fn")]
115        pub const fn $fn_name(&$self_, $($arg : $typ,)*) $body
116
117        #[cfg(not(feature = "const_fn"))]
118        pub fn $fn_name(&$self_, $($arg : $typ,)*) $body
119    };
120
121    (pub fn $fn_name:ident(&$self_: ident) -> $ret: ty $body: block ) => {
122        #[cfg(feature = "const_fn")]
123        pub const fn $fn_name(&$self_) -> $ret $body
124
125        #[cfg(not(feature = "const_fn"))]
126        pub fn $fn_name(&$self_) -> $ret $body
127    };
128
129    (pub fn $fn_name:ident(&$self_: ident) -> $body: block ) => {
130        #[cfg(feature = "const_fn")]
131        pub const fn $fn_name(&$self_) $body
132
133        #[cfg(not(feature = "const_fn"))]
134        pub fn $fn_name(&$self_) $body
135    };
136
137}
138
139#[cfg(test)]
140mod tests {
141    const_ft! {
142        pub fn public_with_no_args() -> u32 {
143            1u32
144        }
145    }
146
147    const_ft! {
148        pub fn public_with_args(x: u32) -> u32 {
149            x
150        }
151    }
152
153    const_ft! {
154            pub fn public_with_no_return() {}
155    }
156
157    const_ft! {
158    fn private_with_no_args() -> u32 {
159        1u32
160    }
161    }
162
163    const_ft! {
164        fn private_with_args(x: u32, _y: u32) -> u32 {
165            x
166        }
167    }
168
169    const_ft! {
170        fn private_with_no_return(_x: u32) {}
171    }
172
173    const_ft! {
174        pub(crate) fn pub_crate_with_args(x: u32) -> u32 {
175            x
176        }
177    }
178
179    struct Foo(u32);
180    impl Foo {
181        const_ft! {
182            pub fn pub_with_self(&self, _x: u32) -> u32 {
183                self.0
184            }
185        }
186
187        const_ft! {
188            pub fn pub_with_self_and_no_args(&self) -> u32 {
189                self.0
190            }
191        }
192    }
193
194    #[test]
195    pub fn it_works() {
196        assert_eq!(public_with_no_args(), 1u32);
197        assert_eq!(public_with_args(1u32), 1u32);
198        assert_eq!(private_with_no_args(), 1u32);
199        assert_eq!(private_with_args(1u32, 2u32), 1u32);
200        assert_eq!(pub_crate_with_args(1u32), 1u32);
201
202        public_with_no_return();
203        private_with_no_return(1u32);
204
205        let foo = Foo(1u32);
206        assert_eq!(foo.pub_with_self(1u32), 1u32);
207        assert_eq!(foo.pub_with_self_and_no_args(), 1u32);
208    }
209}