konst/macros/
impl_cmp.rs

1/// For implementing const comparison semi-manually.
2///
3/// # Impls
4///
5/// This macro implements [`ConstCmpMarker`] for all the `impl`d types,
6/// and outputs the methods/associated constants in each of the listed impls.
7///
8/// # Example
9///
10/// ### Generic type
11///
12/// This demonstrates how you can implement equality and ordering comparison for a generic struct.
13///
14/// ```rust
15/// use konst::{const_cmp, const_eq, impl_cmp, try_equal};
16///
17/// use std::{
18///     cmp::Ordering,
19///     marker::PhantomData,
20/// };
21///
22/// pub struct Tupled<T>(u32, T);
23///
24/// impl_cmp!{
25///     impl[T] Tupled<PhantomData<T>>
26///     where[ T: 'static ];
27///
28///     impl[] Tupled<bool>;
29///     impl Tupled<Option<bool>>;
30///     
31///     pub const fn const_eq(&self, other: &Self) -> bool {
32///         const_eq!(self.0, other.0) &&
33///         const_eq!(self.1, other.1)
34///     }
35///     pub const fn const_cmp(&self, other: &Self) -> Ordering {
36///         try_equal!(const_cmp!(self.0, other.0));
37///         try_equal!(const_cmp!(self.1, other.1))
38///     }
39/// }
40///
41/// const CMPS: [(Ordering, bool); 4] = {
42///     let foo = Tupled(3, PhantomData::<u32>);
43///     let bar = Tupled(5, PhantomData::<u32>);
44///     
45///     [
46///         (const_cmp!(foo, foo), const_eq!(foo, foo)),
47///         (const_cmp!(foo, bar), const_eq!(foo, bar)),
48///         (const_cmp!(bar, foo), const_eq!(bar, foo)),
49///         (const_cmp!(bar, bar), const_eq!(bar, bar)),
50///     ]
51/// };
52///
53/// assert_eq!(
54///     CMPS,
55///     [
56///         (Ordering::Equal, true),
57///         (Ordering::Less, false),
58///         (Ordering::Greater, false),
59///         (Ordering::Equal, true),
60///     ]
61/// );
62///
63/// ```
64///
65/// ### Enum
66///
67/// This demonstrates how you can implement equality and ordering comparison for an enum.
68///
69/// ```rust
70/// use konst::{const_cmp, const_eq, impl_cmp, try_equal};
71///
72/// use std::cmp::Ordering;
73///
74/// pub enum Enum {
75///     Tupled(u32, u32),
76///     Unit,
77/// }
78///
79/// impl_cmp!{
80///     impl Enum;
81///     
82///     pub const fn const_eq(&self, other: &Self) -> bool {
83///         match (self, other) {
84///             (Self::Tupled(l0,l1), Self::Tupled(r0, r1)) => *l0 == *r0 && *l1 == *r1,
85///             (Self::Unit, Self::Unit) => true,
86///             _ => false,
87///         }
88///     }
89///     pub const fn const_cmp(&self, other: &Self) -> Ordering {
90///         match (self, other) {
91///             (Self::Tupled(l0,l1), Self::Tupled(r0, r1)) => {
92///                 try_equal!(const_cmp!(*l0, *r0));
93///                 try_equal!(const_cmp!(*l1, *r1))
94///             }
95///             (Self::Tupled{..}, Self::Unit) => Ordering::Less,
96///             (Self::Unit, Self::Unit) => Ordering::Equal,
97///             (Self::Unit, Self::Tupled{..}) => Ordering::Greater,
98///         }
99///     }
100/// }
101///
102/// const CMPS: [(Ordering, bool); 4] = {
103///     let foo = Enum::Tupled(3, 5);
104///     let bar = Enum::Unit;
105///     
106///     [
107///         (const_cmp!(foo, foo), const_eq!(foo, foo)),
108///         (const_cmp!(foo, bar), const_eq!(foo, bar)),
109///         (const_cmp!(bar, foo), const_eq!(bar, foo)),
110///         (const_cmp!(bar, bar), const_eq!(bar, bar)),
111///     ]
112/// };
113///
114/// assert_eq!(
115///     CMPS,
116///     [
117///         (Ordering::Equal, true),
118///         (Ordering::Less, false),
119///         (Ordering::Greater, false),
120///         (Ordering::Equal, true),
121///     ]
122/// );
123///
124/// ```
125///
126/// [`ConstCmpMarker`]: ./polymorphism/trait.ConstCmpMarker.html
127///
128#[cfg(feature = "cmp")]
129#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))]
130#[macro_export]
131macro_rules! impl_cmp {
132    (
133        $($rem:tt)*
134    ) => (
135        $crate::__impl_cmp_recursive!{
136            impls[
137            ]
138            tokens[$($rem)*]
139        }
140    );
141    (
142        $($rem:tt)*
143    ) => (
144        $crate::__impl_cmp_recursive!{
145            impls[
146            ]
147            tokens[$($rem)*]
148        }
149    );
150}
151
152#[doc(hidden)]
153#[macro_export]
154macro_rules! __impl_cmp_recursive{
155    (
156        impls[$($impls:tt)*]
157
158        tokens[
159            $(#[$impl_attr:meta])*
160            impl[$($impl_:tt)*] $type:ty
161            $(where[ $($where:tt)* ])?;
162
163            $($rem:tt)*
164        ]
165    ) => (
166        $crate::__impl_cmp_recursive!{
167
168            impls[
169                $($impls)*
170                (
171                    $(#[$impl_attr])*
172                    impl[$($impl_)*] $type
173                    where[ $($($where)*)? ];
174                )
175            ]
176            tokens[
177                $($rem)*
178            ]
179        }
180    );
181    // The same as the above macro branch, but it doesn't require the `[]` in `impl[]`
182    (
183        impls[$($impls:tt)*]
184
185        tokens[
186            $(#[$impl_attr:meta])*
187            impl $type:ty
188            $(where[ $($where:tt)* ])?;
189
190            $($rem:tt)*
191        ]
192    ) => (
193        $crate::__impl_cmp_recursive!{
194
195            impls[
196                $($impls)*
197                (
198                    $(#[$impl_attr])*
199                    impl[] $type
200                    where[ $($($where)*)? ];
201                )
202            ]
203            tokens[
204                $($rem)*
205            ]
206        }
207    );
208    (
209        impls [ $( $an_impl:tt )+ ]
210        tokens $stuff:tt
211    ) => (
212        $(
213            $crate::__impl_cmp_impl!{
214                $an_impl
215                $stuff
216            }
217        )+
218    );
219}
220
221#[doc(hidden)]
222#[macro_export]
223macro_rules! __impl_cmp_impl {
224    (
225        (
226            $(#[$impl_attr:meta])*
227            impl[$($impl_:tt)*] $type:ty
228            where[ $($where:tt)* ];
229        )
230        [ $($everything:tt)* ]
231    )=>{
232        $(#[$impl_attr])*
233        impl<$($impl_)*> $crate::__::ConstCmpMarker for $type
234        where
235            $($where)*
236        {
237            type Kind = $crate::__::IsNotStdKind;
238            type This = Self;
239        }
240
241        $(#[$impl_attr])*
242        impl<$($impl_)*> $type
243        where
244            $($where)*
245        {
246            $($everything)*
247        }
248    };
249}
250
251#[doc(hidden)]
252#[macro_export]
253macro_rules! __impl_cmp_self_ty {
254    ($self:ty, /*is_std_type*/ true )=>{
255        $crate::__::PWrapper<$self>
256    };
257    ($self:ty, /*is_std_type*/ false )=>{
258        $self
259    };
260
261}