konst/macros/
polymorphism_macros.rs

1#[doc(hidden)]
2#[macro_export]
3macro_rules!  __priv_delegate_const_inner_fn{
4    (
5        $(skip_coerce $(@$_skip:tt@)?;)?
6
7        $(for[$($implg:tt)*])?
8        $(#[$attr:meta])*
9        pub const fn $func:ident $(<$($fnlt:lifetime),* $(,)?>)?(
10            $($idents:ident)* : $l_ty:ty,
11            $rhs:ident: $r_ty:ty $(,)*
12        ) -> $ret:ty $block:block
13    )=>{
14        $(#[$attr])*
15        pub const fn $func<$($($fnlt,)*)? $($($implg)*)?>(
16            $crate::__priv_get_pati_ident!($($idents)*): $l_ty,
17            $rhs: $r_ty,
18        ) -> $ret $block
19    }
20}
21
22#[cfg(feature = "cmp")]
23#[doc(hidden)]
24#[macro_export]
25macro_rules!  __priv_delegate_const_inner_cmpwrapper{
26    (
27        ($docs:expr, $cw_method:ident, $returns:ty)
28
29        $(skip_coerce $(@$_skip:tt@)?;)*
30
31        $( for[$($implg:tt)*] )?
32        $(#[$attr:meta])*
33        pub const fn $func:ident $(<$($fnlt:lifetime),* $(,)?>)?(
34            $($idents:ident)* : $l_ty:ty,
35            $rhs:ident: $r_ty:ty $(,)*
36        ) -> $ret:ty $block:block
37    ) => {
38        $crate::__priv_std_kind_impl!{
39            $(skip_coerce $(@$_skip@)?;)*
40            impl[$($($implg)*)?] $l_ty
41        }
42
43        impl<$($($implg)*)?> $crate::__::CmpWrapper<$l_ty> {
44            #[doc = $docs]
45            #[inline]
46            pub const fn $cw_method<$($($fnlt,)*)?>(
47                &self,
48                other: $crate::__priv_ref_if_nonref!(($($idents)*) $r_ty),
49            ) -> $returns {
50                $func(
51                    $crate::__priv_copy_if_nonref!(($($idents)*) self.0),
52                    $crate::__priv_deref_if_nonref!(($($idents)*) other)
53                )
54            }
55        }
56    }
57}
58
59/// `__delegate_const_eq` allows:
60/// - defining a free function,
61/// - defining an inherent `cosnt_eq` method on CmpWrapper that delegates to that free function.
62/// - ConstCmpMarker impl for the first parameter type
63/// - Add a coerce inhenrent method for IsAConstCmpMarker
64///
65#[cfg(not(feature = "cmp"))]
66#[doc(hidden)]
67#[macro_export]
68macro_rules! __delegate_const_eq{
69    ( $($input:tt)* )=>{
70        $crate::__priv_delegate_const_inner_fn!{ $($input)* }
71    }
72}
73
74#[cfg(feature = "cmp")]
75#[doc(hidden)]
76#[macro_export]
77macro_rules!  __delegate_const_eq{
78    ( $($input:tt)* )=>{
79        $crate::__priv_delegate_const_inner_fn!{ $($input)* }
80
81        $crate::__priv_delegate_const_inner_cmpwrapper!{
82            (
83                "Compares `self` and `other` for equality.",
84                const_eq,
85                bool
86            )
87
88            $($input)*
89        }
90    };
91}
92
93#[cfg(not(feature = "cmp"))]
94#[doc(hidden)]
95#[macro_export]
96macro_rules! __delegate_const_ord{
97    ($($input:tt)*)=>{
98        $crate::__priv_delegate_const_inner_fn!{ $($input)* }
99    }
100}
101
102#[cfg(feature = "cmp")]
103#[doc(hidden)]
104#[macro_export]
105macro_rules! __delegate_const_ord{
106    ( $($input:tt)* )=>{
107        $crate::__priv_delegate_const_inner_fn!{ $($input)* }
108
109        $crate::__priv_delegate_const_inner_cmpwrapper!{
110            (
111                "Compares `self` and `other` for ordering.",
112                const_cmp,
113                $crate::__::Ordering
114            )
115
116            skip_coerce;
117
118            $($input)*
119        }
120    };
121}
122
123#[cfg(feature = "cmp")]
124#[doc(hidden)]
125#[macro_export]
126macro_rules! __priv_copy_if_nonref {
127    ((ref $ident:ident) $expr:expr) => {
128        &$expr
129    };
130    ((copy $ident:ident) $expr:expr) => {
131        $expr
132    };
133}
134#[cfg(feature = "cmp")]
135#[doc(hidden)]
136#[macro_export]
137macro_rules! __priv_deref_if_nonref {
138    ((ref $ident:ident) $expr:expr) => {
139        $expr
140    };
141    ((copy $ident:ident) $expr:expr) => {
142        *$expr
143    };
144}
145
146#[cfg(feature = "cmp")]
147#[doc(hidden)]
148#[macro_export]
149macro_rules! __priv_ref_if_nonref {
150    ((ref $ident:ident) $ty:ty) => {
151        $ty
152    };
153    ((copy $ident:ident) $ty:ty) => {
154        &$ty
155    };
156}
157
158#[doc(hidden)]
159#[macro_export]
160macro_rules! __priv_get_pati_ident {
161    (ref $ident:ident) => {
162        $ident
163    };
164    (copy $ident:ident) => {
165        $ident
166    };
167}
168
169#[doc(hidden)]
170#[macro_export]
171macro_rules! __priv_std_kind_impl {
172    (
173        impl[$($impl:tt)*] $self:ty
174        $(where[ $($where_:tt)* ])?
175    )=>{
176        impl<$($impl)*> $crate::__::ConstCmpMarker for $self
177        where
178            $($($where_)*)?
179        {
180            type Kind = $crate::__::IsStdKind;
181            type This = Self;
182        }
183
184        impl<$($impl)* __T> $crate::__::IsAConstCmpMarker<$crate::__::IsStdKind, $self, __T>
185        where
186            $($($where_)*)?
187        {
188            ///
189            #[inline(always)]
190            pub const fn coerce(self, reference: &$self) -> $crate::__::CmpWrapper<$self> {
191                $crate::__::CmpWrapper(*reference)
192            }
193        }
194    };
195    (skip_coerce $($anything:tt)*)=>{};
196}
197
198/// Coerces `reference` to a type that has a `const_eq` or `const_cmp` method.
199///
200/// # Behavior
201///
202/// This requires arguments to implement the [`ConstCmpMarker`] trait.
203///
204/// When a type from the standard library is passed,
205/// this wraps it inside a [`CmpWrapper`],
206/// which declares `const_eq` and `const_cmp` methods for many standard library types.
207///
208/// When a user-defined type is used, this evaluates to a reference to the passed in value,
209/// dereferencing it as necessary.
210///
211/// # Limitations
212///
213/// The parameter(s) must be concrete types, and have a fully inferred type.
214/// eg: if you pass an integer literal it must have a suffix to indicate its type.
215///
216/// # Example
217///
218/// ```rust
219/// use konst::{
220///     polymorphism::CmpWrapper,
221///     coerce_to_cmp, impl_cmp,
222/// };
223///
224/// struct Unit;
225///
226/// impl_cmp!{
227///     impl Unit;
228///     
229///     pub const fn const_eq(&self, other: &Self) -> bool {
230///         true
231///     }
232/// }
233///
234/// let wrapper: CmpWrapper<i32> = coerce_to_cmp!(0i32);
235/// assert!( wrapper.const_eq(&0));
236/// assert!(!wrapper.const_eq(&1));
237///
238/// let unit: &Unit = coerce_to_cmp!(Unit);
239/// assert!( unit.const_eq(&Unit));
240///
241///
242///
243///
244///
245///
246/// ```
247///
248/// [`ConstCmpMarker`]: ./polymorphism/trait.ConstCmpMarker.html
249/// [`CmpWrapper`]: ./polymorphism/struct.CmpWrapper.html
250///
251#[cfg(feature = "cmp")]
252#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp")))]
253#[macro_export]
254macro_rules! coerce_to_cmp {
255    ($reference:expr $(,)*) => {{
256        match $reference {
257            ref reference => {
258                let marker = $crate::__::IsAConstCmpMarker::NEW;
259                if false {
260                    marker.infer_type(reference);
261                }
262                marker.coerce(marker.unreference(reference))
263            }
264        }
265    }};
266    ($left:expr, $right:expr $(,)*) => {{
267        match (&$left, &$right) {
268            (left, right) => {
269                let l_marker = $crate::__::IsAConstCmpMarker::NEW;
270                let r_marker = $crate::__::IsAConstCmpMarker::NEW;
271                if false {
272                    l_marker.infer_type(left);
273                    r_marker.infer_type(right);
274                }
275                (
276                    l_marker.coerce(l_marker.unreference(left)),
277                    r_marker.unreference(right),
278                )
279            }
280        }
281    }};
282}