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 &|$func, $($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
121 $crate::crecurse!(@macro_def ($) $func $($cargs)*);
122 $body
123 },
124 $($args,)* $(&mut $cargs,)*
125 )
126 }
127 }};
128 (@default [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => {
129 $crate::crecurse!(@default [$($caps)*], fn $func ($($argstt)*) -> () $($rest)*)
130 };
131 ($([$($caps:tt)*],)? fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => {
132 $crate::crecurse!(@default [$($($caps)*)?], fn $func ($($args: $argsty),*) $($rest)*)
133 };
134
135 (
136 @unsafe [$($cargs:ident: $cargsty:ty),* $(,)?],
137 fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
138 ) => {{
139 fn call<F>(f: &mut F, $($args: $argsty,)* $($cargs: &mut $cargsty,)*) -> $ret
140 where
141 F: FnMut(&mut dyn FnMut($($argsty,)* $(&mut $cargsty,)*) -> $ret, $($argsty,)* $(&mut $cargsty,)*) -> $ret,
142 {
143 let fp = f as *mut F;
144 (unsafe { &mut *fp })(
145 &mut |$($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
146 call(unsafe { &mut *fp }, $($args,)* $($cargs,)*)
147 },
148 $($args,)* $($cargs,)*
149 )
150 }
151 |$($args: $argsty,)*| -> $ret {
152 call(
153 &mut |$func, $($args: $argsty,)* $($cargs: &mut $cargsty,)*| -> $ret {
154 $crate::crecurse!(@macro_def ($) $func $($cargs)*);
155 $body
156 },
157 $($args,)* $(&mut $cargs,)*
158 )
159 }
160 }};
161
162 (@unsafe [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => {
163 $crate::crecurse!(@unsafe [$($caps)*], fn $func ($($argstt)*) -> () $($rest)*)
164 };
165 ($([$($caps:tt)*],)? unsafe fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => {
166 $crate::crecurse!(@unsafe [$($($caps)*)?], fn $func ($($args: $argsty),*) $($rest)*)
167 };
168 ($($t:tt)*) => {
169 ::std::compile_error!(::std::concat!("invalid input: ", ::std::stringify!($($t)*)))
170 };
171}
172
173#[macro_export]
197macro_rules! memorize {
198 (
199 @inner [$map:ident, $Map:ty, $init:expr]
200 fn $name:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
201 ) => {
202 let mut $map: $Map = $init;
203 #[allow(unused_mut)]
204 let mut $name = $crate::crecurse!(
205 [$map: $Map],
206 fn $name ($($args: $argsty),*) -> $ret {
207 if let Some(value) = $map.get(&($($args,)*)).cloned() {
208 value
209 } else {
210 let value = (|| $body)();
211 $map.insert(($($args,)*), value.clone());
212 value
213 }
214 }
215 );
216 };
217 (fn $name:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block) => {
218 $crate::memorize!(
219 @inner [
220 __memorize_map,
221 ::std::collections::HashMap<($($argsty,)*), $ret>,
222 ::std::default::Default::default()
223 ]
224 fn $name ($($args: $argsty),*) -> $ret $body
225 );
226 }
227}