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}