Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- macro_rules! using {
- ([$($bindings:tt)*] -> $Ret:ty $block:block) => {
- _using_impl!{@munch{
- toks: [$($bindings)*]
- done: []
- body: [$block]
- ret: [$Ret]
- }
- }};
- ([$($bindings:tt)*] $($body:tt)+) => {
- _using_impl!{@munch{
- toks: [$($bindings)*]
- done: []
- body: [{$($body)+}]
- ret: [_]
- }
- }};
- }
- macro_rules! _using_impl {
- // FIXME: the reason this matches `ref` and `ref mut` with :tts was that I *thought* it would
- // improve the spans used by unused_mut warnings.
- // ...this backfired.
- //
- // warning: variable does not need to be mutable
- // 166 | pat: [$a $ident]
- // | ^^^^^^ help: remove this `mut`
- // Here we are trying to extract patterns of the form `ident`, `ref ident`, or `ref mut ident`,
- // each optionally followed by a type. We must do this with a muncher, because we need the ident.
- // Just `x`
- (@munch{
- // FIXME when $()? is stabilized, it should be used for $Type.
- // (currently, more than one type annotation is allowed and the rest are silently ignored
- // due to how we handle the default type of `_`. This is undesirable but hard to fix)
- toks: [$ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
- done: [$($done:tt)*]
- body: $body:tt
- ret: $ret:tt
- }) => {
- _using_impl!{@munch{
- toks: [$($more_bindings)*]
- done: [$($done)* {
- ident: [$ident]
- pat: [$ident]
- // type: will be a list containing one or two types, only the first of which will be used.
- // By inserting `_` at the end, it gets used as the default.
- type: [$([$Type])* [_]]
- }]
- body: $body
- ret: $ret
- }}
- };
- // no trailing comma
- (@munch{ toks: [$ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
- _using_impl!{@munch{ toks: [$ident $(: $Type)*,] $($rest)+}}
- };
- // `ref x`, or `mut x`
- (@munch{
- toks: [$a:tt $ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
- done: [$($done:tt)*]
- body: $body:tt
- ret: $ret:tt
- }) => {
- _using_impl!{@munch{
- toks: [$($more_bindings)*]
- done: [$($done)* {
- ident: [$ident]
- pat: [$a $ident]
- type: [$([$Type])* [_]]
- }]
- body: $body
- ret: $ret
- }}
- };
- (@munch{ toks: [$a:tt $ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
- _using_impl!{@munch{ toks: [$a $ident $(: $Type)*,] $($rest)+}}
- };
- // `ref mut x`
- (@munch{
- toks: [$a:tt $b:tt $ident:ident $(: $Type:ty)* , $($more_bindings:tt)*]
- done: [$($done:tt)*]
- body: $body:tt
- ret: $ret:tt
- }) => {
- _using_impl!{@munch{
- toks: [$($more_bindings)*]
- done: [$($done)* {
- ident: [$ident]
- pat: [$a $b $ident]
- type: [$([$Type])* [_]]
- }]
- body: $body
- ret: $ret
- }}
- };
- (@munch{ toks: [$a:tt $b:tt $ident:ident $(: $Type:ty)*] $($rest:tt)+ }) => {
- _using_impl!{@munch{ toks: [$a $b $ident $(: $Type)*,] $($rest)+}}
- };
- // no more! no more!
- (@munch{ toks: [] done:$bindings:tt body:$body:tt ret:$ret:tt }) => {
- _using_impl!{@finish{ bindings:$bindings body:$body ret:$ret }}
- };
- (@finish{
- bindings: [$({
- ident: [$ident:ident]
- pat: [$pat:pat]
- type: [[$Type:ty] $($unused_types:tt)*]
- })*]
- body: [$body:block]
- ret: [$Ret:ty]
- }) => {{
- $(let $pat: $Type = $ident;)*
- $crate::CallHelper(($($ident),*)).call(|$($ident),*| $body)
- }};
- ($($tok:tt)+) => {
- compile_error!(concat!{"using! macro: unknown error at `", stringify!{$($tok)+}}, "`")
- };
- }
- /// For calling a function in a manner that tricks rust into applying
- /// its closure argument type inference hack
- #[doc(hidden)]
- pub struct CallHelper<T>(T);
- macro_rules! impl_call_helper_all {
- ($a0:ident : $A0:ident, $($a:ident : $A:ident,)*) => {
- impl_call_helper!{ $a0:$A0, $($a:$A,)* }
- impl_call_helper_all!{ $($a:$A,)* }
- };
- () => {};
- }
- macro_rules! impl_call_helper {
- ($($a:ident : $A:ident,)*) => {
- impl<$($A),*> CallHelper<($($A,)*)> {
- pub fn call<R>(
- self,
- // this is deliberately `fn` instead of `impl FnOnce`; that's how access
- // to unlisted bindings is forbidden. (albeit through an awful type error)
- function: fn($($A),*) -> R,
- ) -> R {
- let CallHelper(($($a,)*)) = self;
- function($($a),*)
- }
- }
- };
- }
- impl_call_helper_all!{
- a:A, b:B, c:C, d:D, e:E, f:F,
- g:G, h:H, i:I, j:J, k:K, l:L,
- m:M, n:N, o:O, p:P, q:Q,
- s:S, t:T, u:U, v:V, w:W, x:X,
- y:Y, z:Z,
- }
- fn main() {
- let a = vec![()];
- let b = vec![()];
- let mut c = vec![()];
- let d = vec![()];
- let mut e = vec![()];
- using!{[b, mut c, ref d, ref mut e] {
- let _ = b; // b is Vec<()>. It was moved.
- c.sort(); // c is Vec<()>. It was moved.
- let _ = d.iter(); // d is &Vec<()>
- let _ = e.iter_mut(); // e is &mut Vec<()>
- // let _ = a.iter(); // a cannot be used.
- }}
- }
Add Comment
Please, Sign In to add comment