Guest User

Untitled

a guest
Jul 11th, 2018
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.42 KB | None | 0 0
  1. macro_rules! using {
  2. ([$($bindings:tt)*] -> $Ret:ty $block:block) => {
  3. _using_impl!{@munch{
  4. toks: [$($bindings)*]
  5. done: []
  6. body: [$block]
  7. ret: [$Ret]
  8. }
  9. }};
  10. ([$($bindings:tt)*] $($body:tt)+) => {
  11. _using_impl!{@munch{
  12. toks: [$($bindings)*]
  13. done: []
  14. body: [{$($body)+}]
  15. ret: [_]
  16. }
  17. }};
  18. }
  19.  
  20. macro_rules! _using_impl {
  21. // FIXME: the reason this matches `ref` and `ref mut` with :tts was that I *thought* it would
  22. // improve the spans used by unused_mut warnings.
  23. // ...this backfired.
  24. //
  25. // warning: variable does not need to be mutable
  26. // 166 | pat: [$a $ident]
  27. // | ^^^^^^ help: remove this `mut`
  28.  
  29.  
  30. // Here we are trying to extract patterns of the form `ident`, `ref ident`, or `ref mut ident`,
  31. // each optionally followed by a type. We must do this with a muncher, because we need the ident.
  32.  
  33. // Just `x`
  34. (@munch{
  35. // FIXME when $()? is stabilized, it should be used for $Type.
  36. // (currently, more than one type annotation is allowed and the rest are silently ignored
  37. // due to how we handle the default type of `_`. This is undesirable but hard to fix)
  38. toks: [$ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
  39. done: [$($done:tt)*]
  40. body: $body:tt
  41. ret: $ret:tt
  42. }) => {
  43. _using_impl!{@munch{
  44. toks: [$($more_bindings)*]
  45. done: [$($done)* {
  46. ident: [$ident]
  47. pat: [$ident]
  48. // type: will be a list containing one or two types, only the first of which will be used.
  49. // By inserting `_` at the end, it gets used as the default.
  50. type: [$([$Type])* [_]]
  51. }]
  52. body: $body
  53. ret: $ret
  54. }}
  55. };
  56. // no trailing comma
  57. (@munch{ toks: [$ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
  58. _using_impl!{@munch{ toks: [$ident $(: $Type)*,] $($rest)+}}
  59. };
  60.  
  61. // `ref x`, or `mut x`
  62. (@munch{
  63. toks: [$a:tt $ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
  64. done: [$($done:tt)*]
  65. body: $body:tt
  66. ret: $ret:tt
  67. }) => {
  68. _using_impl!{@munch{
  69. toks: [$($more_bindings)*]
  70. done: [$($done)* {
  71. ident: [$ident]
  72. pat: [$a $ident]
  73. type: [$([$Type])* [_]]
  74. }]
  75. body: $body
  76. ret: $ret
  77. }}
  78. };
  79. (@munch{ toks: [$a:tt $ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
  80. _using_impl!{@munch{ toks: [$a $ident $(: $Type)*,] $($rest)+}}
  81. };
  82.  
  83. // `ref mut x`
  84. (@munch{
  85. toks: [$a:tt $b:tt $ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
  86. done: [$($done:tt)*]
  87. body: $body:tt
  88. ret: $ret:tt
  89. }) => {
  90. _using_impl!{@munch{
  91. toks: [$($more_bindings)*]
  92. done: [$($done)* {
  93. ident: [$ident]
  94. pat: [$a $b $ident]
  95. type: [$([$Type])* [_]]
  96. }]
  97. body: $body
  98. ret: $ret
  99. }}
  100. };
  101. (@munch{ toks: [$a:tt $b:tt $ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
  102. _using_impl!{@munch{ toks: [$a $b $ident $(: $Type)*,] $($rest)+}}
  103. };
  104.  
  105. // no more! no more!
  106. (@munch{ toks: [] done:$bindings:tt body:$body:tt ret:$ret:tt }) => {
  107. _using_impl!{@finish{ bindings:$bindings body:$body ret:$ret }}
  108. };
  109.  
  110. (@finish{
  111. bindings: [$({
  112. ident: [$ident:ident]
  113. pat: [$pat:pat]
  114. type: [[$Type:ty] $($unused_types:tt)*]
  115. })*]
  116. body: [$body:block]
  117. ret: [$Ret:ty]
  118. }) => {{
  119. $(let $pat: $Type = $ident;)*
  120. $crate::CallHelper(($($ident),*)).call(|$($ident),*| $body)
  121. }};
  122.  
  123. ($($tok:tt)+) => {
  124. compile_error!(concat!{"using! macro: unknown error at `", stringify!{$($tok)+}}, "`")
  125. };
  126. }
  127.  
  128. /// For calling a function in a manner that tricks rust into applying
  129. /// its closure argument type inference hack
  130. #[doc(hidden)]
  131. pub struct CallHelper<T>(T);
  132.  
  133. macro_rules! impl_call_helper_all {
  134. ($a0:ident : $A0:ident, $($a:ident : $A:ident,)*) => {
  135. impl_call_helper!{ $a0:$A0, $($a:$A,)* }
  136. impl_call_helper_all!{ $($a:$A,)* }
  137. };
  138. () => {};
  139. }
  140. macro_rules! impl_call_helper {
  141. ($($a:ident : $A:ident,)*) => {
  142. impl<$($A),*> CallHelper<($($A,)*)> {
  143. pub fn call<R>(
  144. self,
  145. // this is deliberately `fn` instead of `impl FnOnce`; that's how access
  146. // to unlisted bindings is forbidden. (albeit through an awful type error)
  147. function: fn($($A),*) -> R,
  148. ) -> R {
  149. let CallHelper(($($a,)*)) = self;
  150. function($($a),*)
  151. }
  152. }
  153. };
  154. }
  155. impl_call_helper_all!{
  156. a:A, b:B, c:C, d:D, e:E, f:F,
  157. g:G, h:H, i:I, j:J, k:K, l:L,
  158. m:M, n:N, o:O, p:P, q:Q,
  159. s:S, t:T, u:U, v:V, w:W, x:X,
  160. y:Y, z:Z,
  161. }
  162.  
  163.  
  164. fn main() {
  165. let a = vec![()];
  166. let b = vec![()];
  167. let mut c = vec![()];
  168. let d = vec![()];
  169. let mut e = vec![()];
  170.  
  171. using!{[b, mut c, ref d, ref mut e] {
  172. let _ = b; // b is Vec<()>. It was moved.
  173. c.sort(); // c is Vec<()>. It was moved.
  174. let _ = d.iter(); // d is &Vec<()>
  175. let _ = e.iter_mut(); // e is &mut Vec<()>
  176. // let _ = a.iter(); // a cannot be used.
  177. }}
  178. }
Add Comment
Please, Sign In to add comment