foundationdb_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(clippy::unreadable_literal)]
5include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7/// Defines the FDB_API_VERSION constant and generates the `if_cfg_api_versions` macro
8/// from a list of (name, number) versions.
9///
10/// `if_cfg_api_versions` has one branch for all possible version combinations:
11/// - (min = ...)
12/// - (max = ...)
13/// - (min = ..., max = ...) with min < max
14///
15/// For macro expansion reasons, we need to generate all the branches in a single expansion,
16/// so this macro uses accumulators to gather all branch data before expanding it in one go.
17/// In short, this is a combinatorial generator. Given `[0, 1, 2, 3]` it generates branches for:
18/// - (min = 0)
19/// - (min = 1)
20/// - (min = 2)
21/// - (min = 3)
22/// - (max = 0)
23/// - (max = 1)
24/// - (max = 2)
25/// - (max = 3)
26/// - (min = 0, max = 1)
27/// - (min = 0, max = 2)
28/// - (min = 0, max = 3)
29/// - (min = 1, max = 2)
30/// - (min = 1, max = 3)
31/// - (min = 2, max = 3)
32macro_rules! versions_expand {
33    ($(($version_name:tt, $version:tt)),+ $(,)?) => {
34        // Entry point: start with a list of (version_name, version_number)
35        // define the FDB_API_VERSION constant
36        $(
37            #[cfg(feature = $version_name)]
38            pub const FDB_API_VERSION: u32 = $version;
39        )*
40        // Call the "@pre" phase with:
41        // - visited_versions: []
42        // - remaining_versions: versions
43        // - acc2: [] (will store min branches)
44        // - acc3: [] (will store max branches)
45        versions_expand!(@pre [][$(($version_name, $version))+][][]);
46    };
47    (@pre [$($max:tt)*][$min:tt $($other:tt)*][$(($($acc2:tt)*))*][$(($($acc3:tt)*))*]) => {
48        // "@pre" phase generates (min = ...) and (max = ...) branches
49        // While remaining_versions is not empty:
50        // - move one version from remaining to visited
51        // - add one "min" branch to acc2
52        // - add one "max" branch to acc3
53        versions_expand!(@pre [$($max)* $min][$($other)*][$(($($acc2)*))* ($min $($other)*)][$(($($acc3)*))* ($min $($max)*)]);
54    };
55    (@pre [$min:tt $($version:tt)*][] $acc2:tt $acc3:tt) => {
56        // remaining_versions is empty: end of "@pre" phase
57        // Call the "@mid" phase with:
58        // - min_range: [versions[0]]
59        // - max_range: versions[1..]
60        // - acc1: [] (will store min-max combination branches)
61        // - acc2: min_branches
62        // - acc3: max_branches
63        versions_expand!(@mid [$min][$($version)*][] $acc2 $acc3);
64    };
65    (@mid [$min:tt $($version:tt)*][$max:tt $($other:tt)*][$(($($acc1:tt)*))*] $acc2:tt $acc3:tt) => {
66        // "@mid" phase generates all (min = ..., max = ...) branches
67        // This step generates all pairs for the current min
68        // While the max_range is not empty:
69        // - let max be the smallest version in max_range
70        // - add the "min max" branch to acc1
71        // - move max to the min_range
72        versions_expand!(@mid [$min $($version)* $max][$($other)*][$(($($acc1)*))* ($min $max $($version)*)] $acc2 $acc3);
73    };
74    (@mid [$drop:tt $min:tt $($version:tt)*][] $acc1:tt $acc2:tt $acc3:tt) => {
75        // max_range is empty: end of inner "@mid" loop
76        // - drop current min
77        // - set the second smallest version in min_range as new min
78        // - set all remaining versions as the max_range
79        versions_expand!(@mid [$min][$($version)*] $acc1 $acc2 $acc3);
80    };
81    (@mid [$drop:tt][] $acc1:tt $acc2:tt $acc3:tt) => {
82        // min_range is empty: end of "@mid" phase
83        // Call the "@end" phase with:
84        // - the $ sign so it can use it as a symbol in the macro
85        // - acc1: min_max_branches
86        // - acc2: min_branches
87        // - acc3: max_branches
88        versions_expand!(@end ($) $acc1 $acc2 $acc3);
89    };
90    (@end ($d:tt)
91        [$((($min_name1:tt, $min1:tt) ($max_name1:tt, $max1:tt) $(($version_name1:tt, $version1:tt))*))*]
92        [$((($min_name2:tt, $min2:tt) $(($version_name2:tt, $version2:tt))*))*]
93        [$((($max_name3:tt, $max3:tt) $(($version_name3:tt, $version3:tt))*))*]
94    ) => {
95        // "@end" phase generates the macro in one expansion
96        // For each branch type, generates the appropriate cfg attributes
97
98        /// Similar to `cfg_api_versions` proc-macro, but as a regular macro.
99        /// Unlike proc-macros which are unstable on expressions and non-inlined modules,
100        /// `if_cfg_api_versions` can be used on these places.
101        ///
102        /// Any feature after the "min" and "max" arguments will be joined in the "any" predicate.
103        ///
104        /// ### Constraints:
105        /// - `if/else` always requires block syntax (i.e., `{}` around branches).
106        /// - Avoid using multiple items in a single macro call.
107        /// - Best suited for guarding expressions, single items, or blocks.
108        ///
109        /// ## Behavior
110        /// ### Single statement
111        /// Guard the statment without additional curly braces
112        /// ```rs
113        /// if_cfg_api_versions!(max = 520 => prinln!("foo"));
114        /// // expands to:
115        /// #[cfg(any(feature = "fdb-5_1", feature = "fdb-5_2"))]
116        /// println!("foo");
117        /// ```
118        ///
119        /// ### Muliple statements
120        /// Guard a block wrapping the statments
121        /// ```rs
122        /// if_cfg_api_versions!(max = 520 =>
123        ///     prinln!("foo");
124        ///     prinln!("bar");
125        /// );
126        /// // expands to:
127        /// #[cfg(any(feature = "fdb-5_1", feature = "fdb-5_2"))]
128        /// {
129        ///     println!("foo");
130        ///     println!("bar");
131        /// }
132        /// ```
133        ///
134        /// ### Single Item (e.g., `mod`, `fn`, etc.)
135        /// Guard the item without additional culry braces
136        /// ```rs
137        /// if_cfg_api_versions!(max = 520 => pub mod foo);
138        /// // expands to:
139        /// #[cfg(any(feature = "fdb-5_1", feature = "fdb-5_2"))]
140        /// pub mod foo;
141        /// ```
142        ///
143        /// ### Multiple Items: **NOT RECOMMANDED**
144        /// Only guard the first item (does not add curly braces since it would be invalid syntax)
145        /// ```rs
146        /// if_cfg_api_versions!(max = 520 =>
147        ///     pub mod foo;
148        ///     pub mod bar;
149        /// );
150        /// // expands to:
151        /// #[cfg(any(feature = "fdb-5_1", feature = "fdb-5_2"))]
152        /// pub mod foo;
153        /// pub mod bar; // not guarded
154        /// ```
155        ///
156        /// ### If/Else
157        /// Both branches must be wrapped in curly braces, guard the first branch and the second with the opposite condition
158        /// ```rs
159        /// let result = if_cfg_api_versions!(max = 520 => {
160        ///     println!("5.x");
161        ///     true
162        /// } else {
163        ///     println!("6.0+");
164        ///     false
165        /// });
166        /// // expands to:
167        /// let result = {
168        ///     #[cfg(any(feature = "fdb-5_1", feature = "fdb-5_2"))]
169        ///     {
170        ///         println!("5.x");
171        ///         true
172        ///     }
173        ///     #[cfg(not(any(feature = "fdb-5_1", feature = "fdb-5_2")))]
174        ///     {
175        ///         println!("6.0+");
176        ///         false
177        ///     }
178        /// };
179        /// ```
180        #[macro_export]
181        macro_rules! if_cfg_api_versions {
182            // multiple statements
183            ($d($k:tt = $v:tt),+ => $a:stmt; $d($b:stmt)+) => {
184                if_cfg_api_versions!($d($k=$v),+ => { $a; $d($b)+ })
185            };
186            // min-max branches
187            $(
188                (min=$min1, max=$max1 $d(,feature = $feature:literal)* => {$d($then:tt)*} else {$d($else:tt)*}) => {{
189                    #[cfg(any(feature=$min_name1 $(,feature=$version_name1)* ,feature=$max_name1 $d(,feature=$feature)*))]
190                    { $d($then)* }
191                    #[cfg(not(any(feature=$min_name1 $(,feature=$version_name1)* ,feature=$max_name1 $d(,feature=$feature)*)))]
192                    { $d($else)* }
193                }};
194                (min=$min1, max=$max1 $d(,feature = $feature:literal)* => $d($then:tt)*) => {
195                    #[cfg(any(feature=$min_name1 $(,feature=$version_name1)* ,feature=$max_name1 $d(,feature=$feature)*))]
196                    $d($then)*
197                };
198            )*
199            // min branches
200            $(
201                (min=$min2 $d(,feature = $feature:literal)* => {$d($then:tt)*} else {$d($else:tt)*}) => {{
202                    #[cfg(any(feature=$min_name2 $(,feature=$version_name2)* $d(,feature=$feature)*))]
203                    { $d($then)* }
204                    #[cfg(not(any(feature=$min_name2 $(,feature=$version_name2)* $d(,feature=$feature)*)))]
205                    { $d($else)* }
206                }};
207                (min=$min2 $d(,feature = $feature:literal)* => $d($then:tt)*) => {
208                    #[cfg(any(feature=$min_name2 $(,feature=$version_name2)* $d(,feature=$feature)*))]
209                    $d($then)*
210                };
211            )*
212            // max branches
213            $(
214                (max=$max3 $d(,feature = $feature:literal)* => {$d($then:tt)*} else {$d($else:tt)*}) => {{
215                    #[cfg(any($(feature=$version_name3,)* feature=$max_name3 $d(,feature=$feature)*))]
216                    { $d($then)* }
217                    #[cfg(not(any($(feature=$version_name3,)* feature=$max_name3 $d(,feature=$feature)*)))]
218                    { $d($else)* }
219                }};
220                (max=$max3 $d(,feature = $feature:literal)* => $d($then:tt)*) => {
221                    #[cfg(any($(feature=$version_name3,)* feature=$max_name3 $d(,feature=$feature)*))]
222                    $d($then)*
223                };
224            )*
225            // unsupported versions
226            (min=$min:tt, max=$max:tt  $d(,feature = $feature:literal)* => $d($t:tt)*) => {
227                compile_error!(concat!("Use of unsupported version, or min >= max. Supported: ", $($min2, " " ,)*));
228            };
229            (min=$min:tt $d(,feature = $feature:literal)* => $d($t:tt)*) => {
230                compile_error!(concat!("Use of unsupported version. Supported: ", $($min2, " " ,)*));
231            };
232            (max=$max:tt $d(,feature = $feature:literal)* => $d($t:tt)*) => {
233                compile_error!(concat!("Use of unsupported version. Supported: ", $($min2, " " ,)*));
234            };
235        }
236    };
237}
238
239versions_expand![
240    ("fdb-5_1", 510),
241    ("fdb-5_2", 520),
242    ("fdb-6_0", 600),
243    ("fdb-6_1", 610),
244    ("fdb-6_2", 620),
245    ("fdb-6_3", 630),
246    ("fdb-7_0", 700),
247    ("fdb-7_1", 710),
248    ("fdb-7_3", 730),
249    ("fdb-7_4", 740),
250];