Description
Whenever I use futures_util::select!
from 0.3.0-alpha.19
, I frequently run into the error
recursion limit reached while expanding the macro
$crate::dispatch
It seems like if I have too many match arms within the select! { ... }
macro, regardless of whether they are top-level or not, I get this error.
This means that when I have 4 different futures I'm selecting on, I can't really use match arms on most of them otherwise I get this error.
I can get around this by abstracting the logic into a different function and doing the logic there, which in general is a better approach anyway. But there are times when I want to use some match arms with a break
, and it makes the code harder to read when I abstract the code into functions.
Below are a variety of different examples of how a certain amount of complexity causes the recursion error. Note that it seems like it's somehow a total of complexity, not any certain type.
This gives me the impression that somehow the macro is recursing into the portion of the code that it shouldn't be getting into? But I don't know enough about macros at this point to be able to diagnose.
fn main() {
use futures_util::{select, stream::{self, StreamExt}, FutureExt};
let future = async {
let mut s1 = stream::repeat(0_usize);
let mut s2 = stream::repeat(0_usize);
let mut s3 = stream::repeat(0_usize);
let mut s4 = stream::repeat(0_usize);
let mut s5 = stream::repeat(0_usize);
loop {
/* Single stream with lots of match arms */
select! {
value = s1.next().fuse() => {
match value {
Some(0) => {},
Some(1) => {},
Some(2) => {},
Some(3) => {},
Some(4) => {},
Some(5) => {},
Some(6) => {},
Some(7) => {},
Some(8) => {},
Some(9) => {},
Some(10) => {},
Some(11) => {},
Some(12) => {},
Some(13) => {},
Some(14) => {},
Some(15) => {},
Some(16) => {},
Some(17) => {},
_ => {},
}
},
}
/* Handful of streams with a some match arms */
select! {
value = s1.next().fuse() => {
match value {
Some(0) => {},
Some(1) => {},
Some(2) => {},
Some(3) => {},
_ => {},
}
},
value = s2.next().fuse() => {
match value {
Some(0) => {},
Some(1) => {},
Some(2) => {},
_ => {},
}
},
value = s3.next().fuse() => {
match value {
Some(0) => {},
Some(1) => {},
Some(2) => {},
Some(3) => {},
_ => {},
}
},
}
/* Fair bit of streams with a few match arms */
select! {
value = s1.next().fuse() => {
match value {
Some(0) => {},
_ => {},
}
},
value = s2.next().fuse() => {
match value {
Some(0) => {},
_ => {},
}
},
value = s3.next().fuse() => {
match value {
Some(0) => {},
_ => {},
}
},
value = s4.next().fuse() => {
match value {
Some(0) => {},
_ => {},
}
},
value = s5.next().fuse() => {
match value {
Some(0) => {},
_ => {},
}
},
}
/* Single stream with only two top-level match arms, but lots of sub-match arms */
select! {
value = s1.next().fuse() => {
match value {
Some(val) => match val {
val if val < 10 => match val {
val if val < 10 => match val {
val if val < 10 => match val {
val if val < 10 => match val {
val if val < 10 => match val {
val if val < 10 => match val {
val if val < 10 => match val {
_ => {},
},
_ => {},
},
_ => {},
},
_ => {},
},
_ => {},
},
_ => {},
},
_ => {},
},
_ => {}
},
None => {},
}
}
}
}
};
task::block_on(future);
}