#[macro_export]
macro_rules! switch{
( ref mut $($rem:tt)* )=>{
$crate::switch_inn!{@top [refmut] $($rem)* }
};
( &mut $($rem:tt)* )=>{
$crate::switch_inn!{@top [refmut] $($rem)* }
};
( ref $($rem:tt)* )=>{
$crate::switch_inn!{@top [ref] $($rem)* }
};
( & $($rem:tt)* )=>{
$crate::switch_inn!{@top [ref] $($rem)* }
};
(move $($rem:tt)* )=>{
$crate::switch_inn!{@top [move] $($rem)* }
};
(mut $($rem:tt)* )=>{
compile_error!("Expected `ref`/`ref mut`/`move`,found `mut`")
};
( $($rem:tt)+ )=>{
$crate::switch_inn!{@top [move] $($rem)* }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! switch_inn{
(@top
[$def_access:ident]
$matched:ident;
$($match_arms:tt)+
)=>{
$crate::switch_inn!{
@top_ident
[ $def_access ]
$matched,$matched;
$($match_arms)*
}
};
(@top_ident
[$def_access:ident]
$matched:ident,self;
$($match_arms:tt)+
)=>{
$crate::switch_inn!{
@branch
[ $def_access (unassigned _struc_proxy_ $matched) ]
[ vari() code() default() ]
$($match_arms)*
}
};
(@top_ident
[$def_access:ident]
$matched:ident,$matched2:ident;
$($match_arms:tt)+
)=>{
$crate::switch_inn!{
@branch
[ $def_access (unassigned $matched $matched) ]
[ vari() code() default() ]
$($match_arms)*
}
};
(@top
[$def_access:ident]
$proxy_:ident = $matched:expr ;
$($match_arms:tt)+
)=>{{
#[allow(unused_mut)]
let mut $proxy_=$matched;
$crate::switch_inn!{
@branch
[ $def_access (assigned $proxy_ $proxy_) ]
[ vari() code() default() ]
$($match_arms)*
}
}};
(@top
[$def_access:ident]
$matched:expr;
$($match_arms:tt)+
)=>{
$crate::switch_inn!{
@top
[$def_access]
_struc_proxy_=$matched;
$($match_arms)+
}
};
(@top
[$def_access:ident]
$proxy:ident=$matched:expr=>
$($anything:tt)*
)=>{
compile_error!("\
Expected a `;` to separate the switch header from the switch body\n\
hint: Replace the `=>` with a `;`\n\
")
};
(@top
[$def_access:ident]
$proxy:expr=>
$($anything:tt)*
)=>{
compile_error!("\
Expected a `;` to separate the switch header from the switch body\n\
hint: Replace the `=>` with a `;`\n\
")
};
(@top
[$def_access:ident]
$proxy:expr;
)=>{
compile_error!("expected a non-empty switch")
};
(@top
[$def_access:ident]
$proxy:ident=$matched:expr;
)=>{
compile_error!("expected a non-empty switch")
};
(@finish
[ $def_access:ident ($ass:ident $proxy_:ident $self_:tt) ]
[
vari $variants:tt
code $code:tt
default()
]
)=>{
$crate::switch_inn!{
@finish
[$def_access ($ass $proxy_ $self_)]
[
vari $variants
code $code
default({unsafe{
#![allow(unused_unsafe)]
use structural::pmr::{ GetElseValue, GetVariantCountHack };
let (mut _expected,found,ret)=
structural::pmr::as_phantomdata(&($self_))
.structural_get_variant_count(<_switch_fp_::VariantCount>::NEW)
.get_else_values();
_expected=found;
ret
}})
]
}
};
(@finish
$top:tt
[
vari( $($variant:tt)* )
code(
(
$($first_branch_code:tt)*
)
$((
$($code:tt)*
))*
)
default( $($default:tt)+ )
]
)=>{{
#[allow(non_upper_case_globals)]
pub mod _switch_fp_{
$crate::_switch_tstring_aliases!{
$($variant)*
}
}
$($first_branch_code)*
$(
else $($code)*
)*
else $($default)*
}};
(@branch $top:tt $vars:tt )=>{
$crate::switch_inn!{@finish $top $vars }
};
(@branch $top:tt [ vari $variants:tt code( $($code:tt)* ) default $default_b:tt ]
$(_)? if $cond:expr => $($rem:tt)*
)=>{
$crate::switch_inn!{
@skip_expr
$top
[
vari $variants
code(
$($code)*
(if $cond {
$crate::switch_inn!(@get_expr $($rem)*)
})
)
default $default_b
]
$($rem)*
}
};
(@branch $top:tt [ vari $variants:tt code( $($code:tt)* ) default $default_b:tt ]
$(_)? if let $pat:pat = $expr:expr => $($rem:tt)*
)=>{
$crate::switch_inn!{
@skip_expr
$top
[
vari $variants
code(
$($code)*
(if let $pat = $expr {
$crate::switch_inn!(@get_expr $($rem)*)
})
)
default $default_b
]
$($rem)*
}
};
(@branch $top:tt [ vari $variants:tt code $code:tt default () ]
_ => $($rem:tt)*
)=>{
$crate::switch_inn!{
@assert_last_branch
$top
[
vari $variants
code $code
default ({ $crate::switch_inn!(@get_expr $($rem)*) })
]
$($rem)*
}
};
(@branch $top:tt $vars:tt ref mut $($rem:tt)* )=>{
$crate::switch_inn!(@branch_1 $top $vars [refmut] $($rem)* )
};
(@branch $top:tt $vars:tt ref $($rem:tt)* )=>{
$crate::switch_inn!(@branch_1 $top $vars [ref] $($rem)* )
};
(@branch $top:tt $vars:tt move $($rem:tt)* )=>{
$crate::switch_inn!(@branch_1 $top $vars [move] $($rem)* )
};
(@branch $top:tt $vars:tt mut $($rem:tt)* )=>{
compile_error!("Expected `ref` or `ref mut`,found `mut`")
};
(@branch
[ $def_access:ident $proxy_:tt ]
$vars:tt
$variant:ident
$($rem:tt)+
)=>{
$crate::switch_inn!(@branch_1
[$def_access $proxy_]
$vars
[$def_access]
$variant $($rem)+
)
};
(@branch_1
$top:tt $vars:tt [$access:ident]
$variant:ident => $($rem:tt)*
)=>{
$crate::switch_inn!(@branch_2
$top $vars [$access $variant ()]
$($rem)*
)
};
(@branch_1
$top:tt $vars:tt [$access:ident]
$variant:ident ($($fields:tt)*) => $($rem:tt)*
)=>{
$crate::switch_inn!(@branch_2
$top $vars [$access $variant ($($fields)*)]
$($rem)*
)
};
(@branch_1
$top:tt $vars:tt [$access:ident]
$variant:ident{$($fields:tt)*} => $($rem:tt)*
)=>{
$crate::switch_inn!(@branch_2
$top $vars [$access $variant {$($fields)*}]
$($rem)*
)
};
(@branch_2
[ $def_access:ident ($ass:ident $proxy_:ident $self_:tt) ]
[
vari( $($prev_variants:tt)* )
code( $($code:tt)* )
default $default_b:tt
]
[ $access:ident $variant:ident $fields:tt ]
$($rem:tt)*
)=>{
$crate::switch_inn!{
@skip_expr
[$def_access ($ass $proxy_ $self_)]
[
vari($($prev_variants)* $variant $fields )
code(
$($code)*
(if {
use $crate::pmr::_Structural_BorrowSelf;
$crate::pmr::IsVariant::is_variant_(
$self_._structural_borrow_self(),
_switch_fp_::v::$variant::NEW
)
} {
$crate::switch_inn!{@make_proxy $access $variant ($ass $proxy_ $self_) }
$crate::switch_inn!{
@access_f
[$access $variant ($ass $proxy_ $self_)]
$fields
}
$crate::switch_inn!(@get_expr $($rem)* )
})
)
default $default_b
]
$($rem)*
}
};
(@branch $top:tt $vars:tt $($anything:tt)* )=>{
compile_error!(concat!(
"switch branch has invalid syntax:\n\t`",
stringify!($($anything)*),
"`"
))
};
(@make_proxy $access:ident $variant:ident (unassigned $proxy_:ident $self_:tt) )=>{
$crate::switch_inn!(
@make_proxy_1 $access $variant #[allow(unused_variables)] ($proxy_ $self_)
)
};
(@make_proxy $access:ident $variant:ident (assigned $proxy_:ident $self_:tt) )=>{
$crate::switch_inn!(
@make_proxy_1 $access $variant ($proxy_ $self_)
)
};
(@make_proxy_1 ref $variant:ident $(#$attr:tt)? ($proxy_:ident $self_:tt) )=>{
$(#$attr)?
let $proxy_=unsafe{
use $crate::pmr::_Structural_BorrowSelf;
$crate::pmr::VariantProxy::from_ref(
$self_._structural_borrow_self(),
_switch_fp_::v::$variant::NEW,
)
};
};
(@make_proxy_1 refmut $variant:ident $(#$attr:tt)? ($proxy_:ident $self_:tt) )=>{
$(#$attr)?
let $proxy_=unsafe{
use $crate::pmr::_Structural_BorrowSelf;
$crate::pmr::VariantProxy::from_mut(
$self_._structural_borrow_self_mut(),
_switch_fp_::v::$variant::NEW,
)
};
};
(@make_proxy_1 move $variant:ident $(#$attr:tt)? ($proxy_:ident $self_:tt) )=>{
$(#$attr)?
#[allow(unused_mut)]
let mut $proxy_=unsafe{
$crate::pmr::VariantProxy::new(
$self_,
_switch_fp_::v::$variant::NEW,
)
};
};
(@access_f $vars:tt () )=>{};
(@access_f $vars:tt {} )=>{};
(@access_f $vars:tt ($($patterns:tt)*) )=>{
$crate::switch_inn!{@access_f_1 $vars [] tuple ($($patterns)*) }
};
(@access_f $vars:tt {$($patterns:tt)*} )=>{
$crate::switch_inn!{@access_f_1 $vars [] brace ($($patterns)*) }
};
(@access_f_1
$vars:tt
$prev_fields:tt
brace
( $field_name:tt : $($rem:tt)* )
)=>{
$crate::switch_inn!{@access_f_patt
$vars
$prev_fields
brace
[]
($($rem)*)
}
};
(@access_f_1
$vars:tt
$prev_fields:tt
$vkind:ident
( $($anything:tt)+ )
)=>{
$crate::switch_inn!{@access_f_patt
$vars
$prev_fields
$vkind
[]
( $($anything)* )
}
};
(@access_f_1
[ $access:ident $variant:ident self ]
[ $($variable_pats:tt)* ]
$vkind:ident
()
)=>{
let ($($variable_pats)*)={
use $crate::StructuralExt;
$crate::switch_inn!{@call_field_method $access $variant _struc_proxy_ }
};
};
(@access_f_1
[ $access:ident $variant:ident $proxy_:tt ]
[ $($variable_pats:tt)* ]
$vkind:ident
()
)=>{
let ($($variable_pats)*)={
use $crate::StructuralExt;
$crate::switch_inn!{@call_field_method $access $variant $proxy_ }
};
};
(@access_f_patt
$vars:tt
$prev_fields:tt
$vkind:ident
[]
( _ $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{
@access_f_1
$vars
$prev_fields
$vkind
($($($rem)*)?)
}
};
(@access_f_patt
$vars:tt
[ $($prev_fields:tt)* ]
$vkind:ident
[$($patt_tokens:tt)*]
( $t0:tt $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{@access_f_1
$vars
[ $($prev_fields)* $($patt_tokens)* $t0, ]
$vkind
($($($rem)*)?)
}
};
(@access_f_patt
$vars:tt
[ $($prev_fields:tt)* ]
$vkind:ident
[$($patt_tokens:tt)*]
( $t0:tt $t1:tt $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{@access_f_1
$vars
[ $($prev_fields)* $($patt_tokens)* $t0 $t1, ]
$vkind
($($($rem)*)?)
}
};
(@access_f_patt
$vars:tt
[ $($prev_fields:tt)* ]
$vkind:ident
[$($patt_tokens:tt)*]
( $t0:tt $t1:tt $t2:tt $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{@access_f_1
$vars
[ $($prev_fields)* $($patt_tokens)* $t0 $t1 $t2, ]
$vkind
($($($rem)*)?)
}
};
(@access_f_patt
$vars:tt
$prev_fields:tt
$vkind:ident
[$($patt_tokens:tt)*]
( $t0:tt $t1:tt $t2:tt $($rem:tt)* )
)=>{
$crate::switch_inn!{@access_f_patt
$vars
$prev_fields
$vkind
[$($patt_tokens)* $t0 $t1 $t2]
($($rem)*)
}
};
(@access_f_patt
$vars:tt
[ $($prev_fields:tt)* ]
$vkind:ident
( $variable_name:ident $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{@access_f_1
$vars
[ $($prev_fields)* ($variable_name), ]
$vkind
($($($rem)*)?)
}
};
(@access_f_patt
$vars:tt
[ $($prev_fields:tt)* ]
$vkind:ident
( $variable:tt $(, $($rem:tt)* )? )
)=>{
$crate::switch_inn!{@access_f_1
$vars
[ $($prev_fields)* ($variable), ]
$vkind
($($($rem)*)?)
}
};
(@call_field_method ref $variant:ident ($ass:ident $proxy_:ident $self_:tt) )=>{
$proxy_.fields(_switch_fp_::f::$variant)
};
(@call_field_method refmut $variant:ident ($ass:ident $proxy_:ident $self_:tt) )=>{
$proxy_.fields_mut(_switch_fp_::f::$variant)
};
(@call_field_method move $variant:ident ($ass:ident $proxy_:ident $self_:tt) )=>{
$proxy_.into_fields(_switch_fp_::f::$variant)
};
(@skip_expr $top:tt $vars:tt $expr:expr $(,$($rem:tt)*)? )=>{
$crate::switch_inn!{ @branch $top $vars $($($rem)*)? }
};
(@skip_expr $top:tt $vars:tt $expr:block $($rem:tt)*)=>{
$crate::switch_inn!{ @branch $top $vars $($rem)* }
};
(@get_expr $expr:block $($rem:tt)*)=>{
#[allow(unused_braces)]
$expr
};
(@get_expr $expr:expr $(, $($rem:tt)*)? )=>{
#[allow(unused_braces)]
$expr
};
(@assert_last_branch $top:tt $vars:tt $expr:expr $(,)?)=>{
$crate::switch_inn!{ @branch $top $vars }
};
(@assert_last_branch $top:tt $vars:tt $block:block)=>{
$crate::switch_inn!{ @branch $top $vars }
};
(@assert_last_branch $top:tt $vars:tt $expr:expr , $($rem:tt)+)=>{
$crate::switch_inn!{@last_branch_err $($rem)+}
};
(@assert_last_branch $top:tt $vars:tt $block:block $($rem:tt)+)=>{
$crate::switch_inn!{@last_branch_err $($rem)+}
};
(@last_branch_err $($rem:tt)+)=>{
compile_error!{concat!(
"Expected no switch arms after the default one, found: ",
stringify!($($rem)+)
)}
};
}