tuplez/
macros.rs

1macro_rules! __tuple_unary_ops_impl {
2    ($($tr:ident :: $f:ident ()),* $(,)?) => {
3        $(__tuple_unary_ops_impl!{ @impl $tr $f })*
4    };
5    (@impl $tr:ident $f:ident) => {
6        impl $tr for Unit {
7            type Output = Unit;
8
9            fn $f(self) -> Self::Output {
10                self
11            }
12        }
13
14        impl $tr for &Unit {
15            type Output = Unit;
16
17            fn $f(self) -> Self::Output {
18                Unit
19            }
20        }
21
22        impl<First, Other> $tr for Tuple<First, Other>
23        where
24            First: $tr,
25            Other: $tr + TupleLike,
26        {
27            type Output = Tuple<First::Output, Other::Output>;
28
29            fn $f(self) -> Self::Output {
30                Tuple($tr::$f(self.0), $tr::$f(self.1))
31            }
32        }
33
34        impl<'a, First, Other> $tr for &'a Tuple<First, Other>
35        where
36            &'a First: $tr,
37            &'a Other: $tr,
38            Other: TupleLike,
39        {
40            type Output = Tuple<<&'a First as $tr>::Output, <&'a Other as $tr>::Output>;
41
42            fn $f(self) -> Self::Output {
43                Tuple($tr::$f(&self.0), $tr::$f(&self.1))
44            }
45        }
46    }
47}
48
49macro_rules! __tuple_binary_ops_impl {
50    ($($tr:ident :: $f:ident ()),* $(,)?) => {
51        $(__tuple_binary_ops_impl!{ @impl $tr $f })*
52    };
53    (@impl $tr:ident $f:ident) => {
54        impl<T> $tr<T> for Unit {
55            type Output = T;
56            fn $f(self, rhs: T) -> Self::Output {
57                rhs
58            }
59        }
60
61        impl<T> $tr<T> for &Unit {
62            type Output = T;
63            fn $f(self, rhs: T) -> Self::Output {
64                rhs
65            }
66        }
67
68        impl<First, Other> $tr<Unit> for Tuple<First, Other>
69        where
70            Other: TupleLike
71        {
72            type Output = Self;
73            fn $f(self, _: Unit) -> Self::Output {
74                self
75            }
76        }
77
78        impl<First, Other> $tr<&Unit> for Tuple<First, Other>
79        where
80            Other: TupleLike
81        {
82            type Output = Self;
83            fn $f(self, _: &Unit) -> Self::Output {
84                self
85            }
86        }
87
88        impl<First, Other> $tr<Unit> for &Tuple<First, Other>
89        where
90            Tuple<First, Other>: Clone,
91            Other: TupleLike
92        {
93            type Output = Tuple<First, Other>;
94            fn $f(self, _: Unit) -> Self::Output {
95                Clone::clone(self)
96            }
97        }
98
99        impl<First, Other> $tr<&Unit> for &Tuple<First, Other>
100        where
101            Tuple<First, Other>: Clone,
102            Other: TupleLike
103        {
104            type Output = Tuple<First, Other>;
105            fn $f(self, _: &Unit) -> Self::Output {
106                Clone::clone(self)
107            }
108        }
109
110        impl<First1, Other1, First2, Other2> $tr<Tuple<First2, Other2>> for Tuple<First1, Other1>
111        where
112            First1: $tr<First2>,
113            Other1: $tr<Other2> + TupleLike,
114            Other2: TupleLike,
115        {
116            type Output = Tuple<First1::Output, Other1::Output>;
117            fn $f(self, rhs: Tuple<First2, Other2>) -> Self::Output {
118                Tuple($tr::$f(self.0, rhs.0), $tr::$f(self.1, rhs.1))
119            }
120        }
121
122        impl<'a, First1, Other1, First2, Other2> $tr<&'a Tuple<First2, Other2>> for Tuple<First1, Other1>
123        where
124            First1: $tr<&'a First2>,
125            Other1: $tr<&'a Other2> + TupleLike,
126            Other2: TupleLike,
127        {
128            type Output = Tuple<First1::Output, Other1::Output>;
129            fn $f(self, rhs: &'a Tuple<First2, Other2>) -> Self::Output {
130                Tuple($tr::$f(self.0, &rhs.0), $tr::$f(self.1, &rhs.1))
131            }
132        }
133
134        impl<'a, First1, Other1, First2, Other2> $tr<Tuple<First2, Other2>> for &'a Tuple<First1, Other1>
135        where
136            &'a First1: $tr<First2>,
137            &'a Other1: $tr<Other2>,
138            Other1: TupleLike,
139            Other2: TupleLike,
140        {
141            type Output = Tuple<<&'a First1 as $tr<First2>>::Output, <&'a Other1 as $tr<Other2>>::Output>;
142            fn $f(self, rhs: Tuple<First2, Other2>) -> Self::Output {
143                Tuple($tr::$f(&self.0, rhs.0), $tr::$f(&self.1, rhs.1))
144            }
145        }
146
147        impl<'a, 'b, First1, Other1, First2, Other2> $tr<&'a Tuple<First2, Other2>>
148            for &'b Tuple<First1, Other1>
149        where
150            &'b First1: $tr<&'a First2>,
151            &'b Other1: $tr<&'a Other2>,
152            Other1: TupleLike,
153            Other2: TupleLike,
154        {
155            type Output =
156                Tuple<<&'b First1 as $tr<&'a First2>>::Output, <&'b Other1 as $tr<&'a Other2>>::Output>;
157            fn $f(self, rhs: &'a Tuple<First2, Other2>) -> Self::Output {
158                Tuple($tr::$f(&self.0, &rhs.0), $tr::$f(&self.1, &rhs.1))
159            }
160        }
161    }
162}
163
164macro_rules! __tuple_assignment_ops_impl {
165    ($($tr:ident :: $f:ident ()),* $(,)?) => {
166        $(__tuple_assignment_ops_impl!{ @impl $tr $f })*
167    };
168    (@impl $tr:ident $f:ident) => {
169        impl $tr<Unit> for Unit {
170            fn $f(&mut self, _: Unit) {}
171        }
172
173        impl $tr<&Unit> for Unit {
174            fn $f(&mut self, _: &Unit) {}
175        }
176
177        impl<First1, Other1, First2, Other2> $tr<Tuple<First2, Other2>> for Tuple<First1, Other1>
178        where
179            First1: $tr<First2> + TupleLike,
180            Other1: $tr<Other2> + TupleLike,
181        {
182            fn $f(&mut self, rhs: Tuple<First2, Other2>) {
183                self.0.$f(rhs.0);
184                self.1.$f(rhs.1);
185            }
186        }
187
188        impl<'a, First1, Other1, First2, Other2> $tr<&'a Tuple<First2, Other2>>
189            for Tuple<First1, Other1>
190        where
191            First1: $tr<&'a First2> + TupleLike,
192            Other1: $tr<&'a Other2> + TupleLike,
193        {
194            fn $f(&mut self, rhs: &'a Tuple<First2, Other2>) {
195                self.0.$f(&rhs.0);
196                self.1.$f(&rhs.1);
197            }
198        }
199    }
200}
201
202pub(crate) use __tuple_assignment_ops_impl;
203pub(crate) use __tuple_binary_ops_impl;
204pub(crate) use __tuple_unary_ops_impl;
205
206/// Generate a tuple from a list of expressions.
207///
208/// # Syntax
209///
210/// `tuple!( [ Expr1 [; Count], Expr2 [; Count], ... ] )`
211///
212/// *`[` and `]` only indicate the optional content but not that they need to be input.*
213///
214/// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.*
215///
216/// # Examples
217///
218/// ```
219/// use tuplez::{tuple, Unit};
220///
221/// let tup = tuple!(1, "hello", 3.14);
222/// let tup2 = tuple!("world", 2;3, 9.8);   // Repeat `2` three times
223/// assert_eq!(tup2, tuple!("world", 2, 2, 2, 9.8));
224///
225/// let unit = tuple!();
226/// assert_eq!(unit, Unit);
227/// ```
228///
229/// Remember that the [`tuple!`](crate::tuple!) macro does not directly evaluate expressions, so:
230///
231/// ```
232/// use tuplez::tuple;
233///
234/// let mut x = 0;
235/// assert_eq!(tuple!({x += 1; x}; 3), tuple!(1, 2, 3));
236/// ```
237#[macro_export]
238macro_rules! tuple {
239    ($($t:tt)*) => {
240        $crate::tuple_inner!($crate; $($t)*)
241    };
242}
243
244/// Generate the complete type signature for tuples.
245///
246/// # Syntax
247///
248/// `tuple_t!([T0 [; Count], T1 [; Count], ... ])`
249///
250/// *`[` and `]` only indicate the optional content but not that they need to be input.*
251///
252/// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.*
253///
254/// # Examples
255///
256/// ```
257/// use tuplez::{tuple, tuple_t};
258///
259/// let tup = <tuple_t!(i32, f64, String)>::default();
260/// assert_eq!(tup, tuple!(0, 0.0, String::new()));
261///
262/// let unit: tuple_t!() = From::from(());
263/// assert_eq!(unit, tuple!());
264///
265/// let tup2: tuple_t!(i32, f64;3, i32) = tuple!(1, 2.0, 3.0, 4.0, 5);
266///
267/// fn use_tuple(tup: tuple_t!(i32, &dyn std::fmt::Debug, tuple_t!(String, String))) {
268///     todo!()
269/// }
270/// ```
271#[macro_export]
272macro_rules! tuple_t {
273    ($($t:tt)*) => {
274        $crate::tuple_t_inner!($crate; $($t)*)
275    };
276}
277
278/// Generate patterns for tuples.
279///
280/// # Syntax
281///
282/// `tuple_pat!([#] [Pat0 [; Count], Pat1 [; Count], ... ])`
283///
284/// *`[` and `]` only indicate the optional content but not that they need to be input.*
285///
286/// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.*
287///
288/// # Examples
289///
290/// When the number of patterns you provide is less than the number of elements of the tuple,
291/// the following elements will not be matched. For example:
292///
293/// ```
294/// use tuplez::{tuple, tuple_pat};
295///
296/// let tup = tuple!(3.14, "hello", 1, [9.8]);
297/// let tuple_pat!(a, b, c) = tup;
298/// assert_eq!(a, 3.14);
299/// assert_eq!(b, "hello");
300/// assert_eq!(c, 1);
301/// ```
302///
303/// If you want the last pattern to match all remaining elements, you can add a `#` mark:
304///
305/// ```
306/// use tuplez::{tuple, tuple_pat};
307///
308/// let tup = tuple!(3.14, "hello", 1, [9.8]);
309/// let tuple_pat!(# a, b, c) = tup;
310/// assert_eq!(a, 3.14);
311/// assert_eq!(b, "hello");
312/// assert_eq!(c, tuple!(1, [9.8]));
313/// ```
314///
315/// But this has a bad side effect, even though the number of patterns is equal to the number of elements of the tuple,
316/// the last pattern still matches a tuple containing only one element:
317///
318/// ```
319/// use tuplez::{tuple, tuple_pat};
320///
321/// let tup = tuple!(3.14, "hello", 1, [9.8]);
322/// let tuple_pat!(# a, b, c, d) = tup;
323/// assert_eq!(a, 3.14);
324/// assert_eq!(b, "hello");
325/// assert_eq!(c, 1);
326/// assert_eq!(d, tuple!([9.8]));   // Not `[9.8]`
327/// ```
328///
329/// In this case, just remove the `#` mark. Or, you can also add an extra `_` pattern to unpack the last tuple:
330///
331/// ```
332/// use tuplez::{tuple, tuple_pat};
333///
334/// let tup = tuple!(3.14, "hello", 1, [9.8]);
335/// let tuple_pat!(# a, b, c, d, _) = tup;
336/// assert_eq!(a, 3.14);
337/// assert_eq!(b, "hello");
338/// assert_eq!(c, 1);
339/// assert_eq!(d, [9.8]);
340/// ```
341#[macro_export]
342macro_rules! tuple_pat {
343    ($($t:tt)*) => {
344        $crate::tuple_pat_inner!($crate; $($t)*)
345    };
346}
347
348/// Take the element at a specific index of the tuple and get the remainder.
349///
350/// When the type of element is provided instead of its index, this macro expands to
351/// [`take()`](crate::TupleLike::take()).
352///
353/// The [`pop()`](crate::TupleLike::pop()) and [`pop_front()`](crate::TupleLike::pop_front()) methods
354/// also provide ways to pop elements from the front or back of the tuple.
355///
356/// # Syntax
357///
358/// 1. `take!(Expr; Index)`
359///
360///     **The index must be an integer literal** since procedural macros do not yet support evaluating constants.
361///
362/// 2. `take!(Expr; Type)`
363///
364///     There is currently a restriction: only one element in the tuple can be of the type being searched.
365///
366/// # Examples
367///
368/// Use indices:
369///
370/// ```
371/// use tuplez::{take, tuple};
372///
373/// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]);
374/// let (element, remainder) = take!(tup; 2);
375/// assert_eq!(element, 3.14);
376/// assert_eq!(remainder, tuple!(1, "hello", [1, 2, 3]));
377///
378/// let tup = tuple!(1);
379/// let (element, remainder) = take!(tup; 0);
380/// assert_eq!(element, 1);
381/// assert_eq!(remainder, tuple!());
382/// ```
383///
384/// Use types:
385///
386/// ```
387/// use tuplez::{take, tuple};
388///
389/// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]);
390/// let (element, remainder) = take!(tup; &str);
391/// assert_eq!(element, "hello");
392/// assert_eq!(remainder, tuple!(1, 3.14, [1, 2, 3]));
393///
394/// let tup = tuple!(1);
395/// let (element, remainder) = take!(tup; i32);
396/// assert_eq!(element, 1);
397/// assert_eq!(remainder, tuple!());
398/// ```
399#[macro_export]
400macro_rules! take {
401    ($($t:tt)*) => {
402        $crate::take_inner!($crate; $($t)*)
403    };
404}
405
406/// Split the tuple into two tuples at a specific index.
407///
408/// # Syntax
409///
410/// `split_at!(Expr; Index)`
411///
412/// **The index must be an integer literal** since procedural macros do not yet support evaluating constants.
413///
414/// # Examples
415///
416/// ```
417/// use tuplez::{split_at, tuple};
418///
419/// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]);
420///
421/// let (left, right) = split_at!(tup; 2);
422/// assert_eq!(left, tuple!(1, "hello"));
423/// assert_eq!(right, tuple!(3.14, [1, 2, 3]));
424///
425/// let (left, right) = split_at!(tup; 0);
426/// assert_eq!(left, tuple!());
427/// assert_eq!(right, tup);
428///
429/// let (left, right) = split_at!(tup; 4);
430/// assert_eq!(left, tup);
431/// assert_eq!(right, tuple!());
432/// ```
433#[macro_export]
434macro_rules! split_at {
435    ($($t:tt)*) => {
436        $crate::split_at_inner!($crate; $($t)*)
437    };
438}
439
440/// Provides a simple way to build a mapper that implements [`Mapper`](crate::foreach::Mapper).
441///
442/// # Syntax
443///
444/// ```text
445/// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...]
446/// Rule    = [ < Generic > ] | Variable : InputType | [-> OutputType] { Body } [,] [;]
447///
448/// mapper!( [Rule1 Rule2 ... ] )
449/// ```
450///
451/// *`[` and `]` only indicate the optional content but not that they need to be input.*
452///
453/// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.*
454///
455/// # Explanation
456///
457/// A mapping rule is much like a closure, except that it must annotate the argument type and the return type:
458///
459/// ```text
460/// |x: i32| -> i64 { x as i64 }
461/// ```
462///
463/// Note that it's just like but not really a closure, so you can't capture context variables.
464///
465/// Also supports adding `mut`:
466///
467/// ```text
468/// |mut x: i32| -> i64 { x += 1; x as i64 }
469/// ```
470///
471/// If the return value requires a lifetime, you need to explicitly introduce the lifetime annotation, since Rust binds the lifetime
472/// of return value to the mapper instead of the element by default:
473///
474/// ```text
475/// <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() }
476/// ```
477///
478/// You can omit the return type when the return type is the same as the element type.
479/// Note: Do not misunderstand that the return type is automatically inferred or is a `()`.
480///
481/// ```text
482/// |x: i32| { x + 1 }
483/// ```
484///
485/// You can also introduce generic types like this:
486///
487/// ```text
488/// <T> |x: Option<T>| -> T { x.unwrap() }
489/// ```
490///
491/// Many times, you may also need to add bounds to the generic type:
492///
493/// ```text
494/// <T: ToString> |x: Option<T>| -> String { x.unwrap().to_string() }
495/// ```
496///
497/// Construct mapping rules for all element types in the tuple,
498/// and then combine them in the [`mapper!`](crate::mapper!) macro to traverse the tuple:
499///
500/// ```
501/// use tuplez::{mapper, tuple, TupleLike};
502///
503/// let tup = tuple!(1, "hello", Some(3.14)).foreach(mapper! {
504///     |mut x: i32| -> i64 { x += 1; x as i64 }
505///     <T: ToString> |x: Option<T>| -> String { x.unwrap().to_string() }
506///     <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() }
507/// });
508/// assert_eq!(tup, tuple!(2i64, b"hello" as &[u8], "3.14".to_string()));
509/// ```
510///
511/// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better.
512///
513/// Tip: If you don't want to consume the tuple, call its [`as_ref()`](crate::TupleLike::as_ref()) before traversing.
514/// Likewise, if you want to modify elements of tuple, call its [`as_mut()`](crate::TupleLike::as_mut()) before traversing.
515///
516/// ```
517/// use tuplez::{mapper, tuple, TupleLike};
518///
519/// let mut tup = tuple!(1, "hello", Some(3.14));
520/// let tup2 = tup.as_ref().foreach(mapper! {
521///     |x: &i32| -> i32 { *x + 1 }
522///     <T: ToString> |x: &Option<T>| -> String { x.as_ref().unwrap().to_string() }
523///     <'a> |x: &&'a str| -> &'a [u8] { x.as_bytes() }
524/// });
525/// assert_eq!(tup2, tuple!(2, b"hello" as &[u8], "3.14".to_string()));
526/// assert_eq!(tup, tuple!(1, "hello", Some(3.14)));  // And the original tuple is not consumed
527///
528/// _ = tup.as_mut().foreach(mapper! {
529///     |x: &mut i32| -> () { *x += 1; }
530///     <T: ToString> |x: &mut Option<T>| -> () { x.take(); }
531///     |x: &mut &str| -> () { *x = "world" }
532/// });
533/// assert_eq!(tup, tuple!(2, "world", None));
534/// ```
535#[macro_export]
536macro_rules! mapper {
537    ($($t:tt)*) => {
538        $crate::mapper_inner!($crate; $($t)*)
539    };
540}
541
542/// Provides a simple way to build a folder that implements [`Folder`](crate::fold::Folder).
543///
544/// # Syntax
545///
546/// ```text
547/// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...]
548/// Rule    = [ < Generic > ] | Variable1, Variable2 : InputType | { Body } [,] [;]
549///
550/// folder!( OutputType; [Rule1 Rule2 ... ] )
551/// ```
552///
553/// *`[` and `]` only indicate the optional content but not that they need to be input.*
554///
555/// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.*
556///
557/// # Explanation
558///
559/// A folding rule is much like a closure, except that it must annotate the element type:
560///
561/// ```text
562/// |acc, x: i32| { acc + x }
563/// ```
564///
565/// Note that it's just like but not really a closure, so you can't capture context variables.
566///
567/// You'd better not annotate types for the accumulation value and return value,
568/// because they must to be annotated uniformly. Of course you can do that,
569/// but there would be no advantage other than potential compilation errors.
570///
571/// Also supports adding `mut`:
572///
573/// ```text
574/// |mut acc, mut x: i32| -> i64 { acc += 1; x += 1; acc + x }
575/// ```
576///
577/// You can also introduce generic types like this:
578///
579/// ```text
580/// <T: ToString> |x: Option<T>| { x.unwrap().to_string() }
581/// ```
582///
583/// You need to determine the type of the accumulation value, for example, `i32`.
584/// Then, construct folding rules for all element types in the tuple,
585/// and then combine them in the [`folder!`](crate::folder!) macro to fold the tuple:
586///
587/// ```
588/// use std::convert::AsRef;
589/// use tuplez::{folder, tuple, TupleLike};
590///
591/// let tup = tuple!(1, "2", 3.0);
592/// let result = tup.fold(
593///     folder! {i32;        // Annotate the accumulation value type
594///         |acc, x: i32| { acc + x }
595///         |acc, x: f32| { acc + (x as i32) }
596///         // `str` is a DST, so `?Sized` bound is required.
597///         <T: AsRef<str> + ?Sized> |acc, x: &T| { acc + x.as_ref().parse::<i32>().unwrap() }
598///     },
599///     0
600/// );
601/// assert_eq!(result, 6);
602/// ```
603///
604/// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better.
605#[macro_export]
606macro_rules! folder {
607    ($($t:tt)*) => {
608        $crate::folder_inner!($crate; $($t)*)
609    };
610}
611
612/// Provides a simple way to build a unary predicate that implements [`UnaryPredicate`](crate::predicate::UnaryPredicate).
613///
614/// # Syntax
615///
616/// ```text
617/// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...]
618/// Rule    = [ < Generic > ] | Variable : InputType | { Body } [,] [;]
619///
620/// unary_pred!( [Rule1 Rule2 ... ] )
621/// ```
622///
623/// # Explanation
624///
625/// A unary predicate rule is much like a closure, except that it must annotate the element type,
626/// and what you actually get is the immutable reference to the element rather than itself.
627///
628/// ```text
629/// |x: i32| { *x > 10 }    // The actual type of `x` is `&i32` not `i32`
630/// ```
631///
632/// Note that it's just like but not really a closure, so you can't capture context variables.
633///
634/// You'd better not annotate types for the return value of rules,
635/// because they must return a `bool` value. Of course you can do that,
636/// but there would be no advantage other than potential compilation errors.
637///
638/// You can also introduce generic types like this:
639///
640/// ```text
641/// <T: Fn(i32) -> bool> |f: T| { f(1) }
642/// ```
643///
644/// Construct unary predicate rules for all element types in the tuple,
645/// and then combine them in the [`unary_pred!`](crate::unary_pred!) macro to test the tuple:
646///
647/// ```
648/// use tuplez::{tuple, TupleLike, unary_pred};
649///
650/// let tup = tuple!(1, "2", |x: i32| x >= 0);
651/// let result = tup.all(
652///     unary_pred! {
653///         |x: i32| { *x >= 0 }
654///         |x: &str| { !x.is_empty() }
655///         <T: Fn(i32) -> bool> |f: T| { f(1) }
656///     }
657/// );
658/// assert_eq!(result, true);
659/// ```
660///
661/// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better.
662///
663/// # As a [`Mapper`](crate::foreach::Mapper)
664///
665/// In fact, this macro does not directly implement [`UnaryPredicate<T>`](crate::predicate::UnaryPredicate) for the
666/// underlying type. Instead, it implements [`Mapper<&T, Output=bool>`](crate::foreach::Mapper).
667///
668/// Therefore, you can definitely use it as a [`Mapper`](crate::foreach::Mapper) like this:
669///
670/// ```
671/// use tuplez::{tuple, TupleLike, unary_pred};
672///
673/// let tup = tuple!(Some(1), "", |x: i32| x == 0);
674/// let result = tup.as_ref().foreach(
675///     unary_pred! {
676///         |x: Option<i32>| { x.is_some() }
677///         |x: &str| { !x.is_empty() }
678///         <T: Fn(i32) -> bool> |f: T| { f(1) }
679///     }
680/// );
681///
682/// assert_eq!(result, tuple!(true, false, false));
683/// ```
684#[macro_export]
685macro_rules! unary_pred {
686    ($($t:tt)*) => {
687        $crate::unary_pred_inner!($crate; $($t)*)
688    };
689}