daily pastebin goal
46%
SHARE
TWEET

Untitled

a guest Jul 11th, 2018 63 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top