What are the structures of generated futures?

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?

The source code of async functions that you see gets completely rewritten by the compiler. Futures are state machines with states represented by enum variants.

Every .await needs to save the state of the function at that point (values of variables, currently executed position in the function) in order to be able to return from the function (return Poll::Pending) and resume execution later when polled again.

I'm aware of that. My question is: why the hybrid of fields and variants? variants should stand for the state machine, then what about fields? How do I interpret this structure?

Just got an answer from stackoverflow:

Please let us know in the OP when you cross post.

Edited.

1 Like