Stack Overflow: asynchronous - What are the structures of generated futures? - Stack Overflow
I just learned that we can use #[rustc_layout(debug)]
to dump type layout from this blog post. And I immediately try to use it to see through generated futures.
Here's an example:
#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
use std::future::Future;
use std::time::Duration;
use tokio::sync::{mpsc::UnboundedSender, oneshot::Receiver};
struct Actor {}
impl Actor {
async fn act(&self, mut stop_listener: Receiver<()>, result_channel: UnboundedSender<u64>) {
let part_1_jh = async {
loop {
if stop_listener.try_recv().is_ok() {
return;
}
println!("Hello from p1");
tokio::time::sleep(Duration::from_millis(400)).await;
}
};
let part_2_jh = async {
loop {
println!("Hello from p2");
result_channel.send(43).unwrap();
tokio::time::sleep(Duration::from_millis(700)).await;
}
};
tokio::join!(part_1_jh, part_2_jh);
}
}
#[rustc_layout(debug)]
type Fut<'a> = impl Future;
fn foo(this: &Actor, stop_listener: Receiver<()>, result_channel: UnboundedSender<u64>) -> Fut {
this.act(stop_listener, result_channel)
}
And below is the dumped layout:
error: layout_of({async fn body of Actor::act()}) = Layout {
size: Size(320 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [
Size(296 bytes),
Size(272 bytes),
Size(304 bytes),
Size(313 bytes),
],
memory_index: [
1,
0,
2,
3,
],
},
largest_niche: Some(
Niche {
offset: Size(313 bytes),
value: Int(
I8,
false,
),
valid_range: 0..=3,
},
),
variants: Multiple {
tag: Initialized {
value: Int(
I8,
false,
),
valid_range: 0..=3,
},
tag_encoding: Direct,
tag_field: 3,
variants: [
Layout {
size: Size(320 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [],
memory_index: [],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
},
Layout {
size: Size(320 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [],
memory_index: [],
},
largest_niche: None,
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
},
Layout {
size: Size(320 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [],
memory_index: [],
},
largest_niche: None,
variants: Single {
index: 2,
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
},
Layout {
size: Size(320 bytes),
align: AbiAndPrefAlign {
abi: Align(8 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [
Size(280 bytes),
Size(288 bytes),
Size(0 bytes),
Size(256 bytes),
Size(312 bytes),
],
memory_index: [
2,
3,
0,
1,
4,
],
},
largest_niche: None,
variants: Single {
index: 3,
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
}
The layout has not only fields, but also variants. So I'm wondering what does it represent? Is it like a union
of a struct
that stores async fn arguments and an enum
that stores async states?