1#[macro_export]
71macro_rules! crecurse {
72 (@macro_def ($dol:tt) $name:ident $($cargs:ident)*) => {
73 #[allow(unused_macros)]
74 macro_rules! $name { ($dol($dol args:expr),*) => { $name($dol($dol args,)* $($cargs,)* ) } }
75 };
76
77 (
78 @static [$(($cargs:ident, $cargsexpr:expr, $cargsty:ty))*] [$(,)?],
79 fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
80 ) => {{
81 fn $func($($args: $argsty,)* $($cargs: $cargsty,)*) -> $ret {
82 $crate::crecurse!(@macro_def ($) $func $($cargs)*);
83 $body
84 }
85 |$($args: $argsty,)*| -> $ret { $func($($args,)* $($cargsexpr,)*) }
86 }};
87 (@static [$($pcaps:tt)*] [$(,)?], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => {
88 $crate::crecurse!(@static [$($pcaps)*] [], fn $func ($($argstt)*) -> () $($rest)*)
89 };
90 (@static [$($pcaps:tt)*] [$carg:ident: &mut $cargty:ty, $($caps:tt)*], $($rest:tt)*) => {
91 $crate::crecurse!(@static [$($pcaps)* ($carg, &mut $carg, &mut $cargty)] [$($caps)*], $($rest)*)
92 };
93 (@static [$($pcaps:tt)*] [$carg:ident: &$cargty:ty, $($caps:tt)*], $($rest:tt)*) => {
94 $crate::crecurse!(@static [$($pcaps)* ($carg, &$carg, &$cargty)] [$($caps)*], $($rest)*)
95 };
96 (@static [$($pcaps:tt)*] [$carg:ident: $cargty:ty, $($caps:tt)*], $($rest:tt)*) => {
97 $crate::crecurse!(@static [$($pcaps)* ($carg, $carg, $cargty)] [$($caps)*], $($rest)*)
98 };
99 ($([$($caps:tt)*],)? static fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => {
100 $crate::crecurse!(@static [] [$($($caps)*)?,], fn $func ($($args: $argsty),*) $($rest)*)
101 };
102
103 (
104 @default [$($cargs:ident: $cargsty:ty),* $(,)?],
105 fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
106 ) => {{
107 fn call<F>(f: &F, $($args: $argsty,)* $($cargs: &mut $cargsty,)*) -> $ret
108 where
109 F: Fn(&dyn Fn($($argsty,)* $(&mut $cargsty,)*) -> $ret, $($argsty,)* $(&mut $cargsty,)*) -> $ret,
110 {
111 f(
112 &|$($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
113 call(f, $($args,)* $($cargs,)*)
114 },
115 $($args,)* $($cargs,)*
116 )
117 }
118 |$($args: $argsty,)*| -> $ret {
119 call(
120 #[allow(unused_variables)]
121 &|$func, $($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
122 $crate::crecurse!(@macro_def ($) $func $($cargs)*);
123 $body
124 },
125 $($args,)* $(&mut $cargs,)*
126 )
127 }
128 }};
129 (@default [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => {
130 $crate::crecurse!(@default [$($caps)*], fn $func ($($argstt)*) -> () $($rest)*)
131 };
132 ($([$($caps:tt)*],)? fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => {
133 $crate::crecurse!(@default [$($($caps)*)?], fn $func ($($args: $argsty),*) $($rest)*)
134 };
135
136 (
137 @unsafe [$($cargs:ident: $cargsty:ty),* $(,)?],
138 fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
139 ) => {{
140 fn call<F>(f: &mut F, $($args: $argsty,)* $($cargs: &mut $cargsty,)*) -> $ret
141 where
142 F: FnMut(&mut dyn FnMut($($argsty,)* $(&mut $cargsty,)*) -> $ret, $($argsty,)* $(&mut $cargsty,)*) -> $ret,
143 {
144 let fp = f as *mut F;
145 (unsafe { &mut *fp })(
146 &mut |$($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
147 call(unsafe { &mut *fp }, $($args,)* $($cargs,)*)
148 },
149 $($args,)* $($cargs,)*
150 )
151 }
152 |$($args: $argsty,)*| -> $ret {
153 call(
154 &mut |$func, $($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
155 $crate::crecurse!(@macro_def ($) $func $($cargs)*);
156 $body
157 },
158 $($args,)* $(&mut $cargs,)*
159 )
160 }
161 }};
162
163 (@unsafe [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => {
164 $crate::crecurse!(@unsafe [$($caps)*], fn $func ($($argstt)*) -> () $($rest)*)
165 };
166 ($([$($caps:tt)*],)? unsafe fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => {
167 $crate::crecurse!(@unsafe [$($($caps)*)?], fn $func ($($args: $argsty),*) $($rest)*)
168 };
169 ($($t:tt)*) => {
170 ::std::compile_error!(::std::concat!("invalid input: ", ::std::stringify!($($t)*)))
171 };
172}
173
174#[macro_export]
198macro_rules! memorize {
199 (
200 @inner [$map:ident, $Map:ty, $init:expr]
201 fn $name:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
202 ) => {
203 let mut $map: $Map = $init;
204 #[allow(unused_mut)]
205 let mut $name = $crate::crecurse!(
206 [$map: $Map],
207 fn $name ($($args: $argsty),*) -> $ret {
208 if let Some(value) = $map.get(&($(Clone::clone(&$args),)*)).cloned() {
209 value
210 } else {
211 let value = (|| $body)();
212 $map.insert(($($args,)*), value.clone());
213 value
214 }
215 }
216 );
217 };
218 (fn $name:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block) => {
219 $crate::memorize!(
220 @inner [
221 __memorize_map,
222 ::std::collections::HashMap<($($argsty,)*), $ret>,
223 ::std::default::Default::default()
224 ]
225 fn $name ($($args: $argsty),*) -> $ret $body
226 );
227 }
228}