Какова структура генерируемых фьючерсов?

Я только что узнал, что мы можем использовать #[rustc_layout(debug)] для выгрузки макета шрифта из этого поста в блоге . И я сразу же пытаюсь использовать его, чтобы увидеть сгенерированное будущее.

Вот пример: (Rust Playground)

#![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)
}

И ниже приведен дамп макета:

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),
       }

В макете есть не только поля, но и варианты. Вот мне и интересно, что это означает? Это похоже на unionstruct, который хранит асинхронные аргументы fn, и enum, который хранит асинхронные состояния?

Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
2
0
133
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, сгенерированный тип будущего имеет варианты, соответствующие состояниям будущего. Насколько я знаю, никаких данных за пределами вариантов у него нет. Вы можете получить дополнительную информацию о типе, используя -Zprint-type-sizes, в частности, включая названия вариантов и (в некоторых случаях благодаря моему собственному вкладу) типы полей. Первый из перечисленных и самый крупный тип — это сам act():

type: `{async fn body of Actor::act()}`: 288 bytes, alignment: 8 bytes
    discriminant: 1 bytes
    variant `Unresumed`: 280 bytes
        padding: 239 bytes
        upvar `.stop_listener`: 8 bytes, alignment: 8 bytes
        padding: 16 bytes
        upvar `.self`: 8 bytes, alignment: 8 bytes
        upvar `.result_channel`: 8 bytes
    variant `Suspend0`: 281 bytes
        local `.futures`: 224 bytes, offset: 0 bytes, alignment: 8 bytes
        local `.__awaitee`: 16 bytes, type: tokio::future::poll_fn::PollFn<{closure@/Users/kpreid/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.37.0/src/macros/5:26}>
        upvar `.stop_listener`: 8 bytes
        local `.stop_listener`: 8 bytes
        local `.result_channel`: 8 bytes
        upvar `.self`: 8 bytes
        upvar `.result_channel`: 8 bytes
        local `..coroutine_field4`: 1 bytes, type: bool
    variant `Returned`: 280 bytes
        padding: 239 bytes
        upvar `.stop_listener`: 8 bytes, alignment: 8 bytes
        padding: 16 bytes
        upvar `.self`: 8 bytes, alignment: 8 bytes
        upvar `.result_channel`: 8 bytes
    variant `Panicked`: 280 bytes
        padding: 239 bytes
        upvar `.stop_listener`: 8 bytes, alignment: 8 bytes
        padding: 16 bytes
        upvar `.self`: 8 bytes, alignment: 8 bytes
        upvar `.result_channel`: 8 bytes
    end padding: 6 bytes

При этом вы можете видеть, что начальное состояние (Unresumed) содержит захваченные переменные, а первое и единственное состояние Suspend* должно соответствовать ожиданию реализации tokio::join!. Состояние Returned — это состояние после возвращения будущего Poll::Ready. Я не знаю точно, для чего используется состояние Panicked, но, предположительно, это состояние, оставленное при опросе будущей паники.

Обратите внимание, что по вариантам разбросаны «отступы»; здесь дело в том, что поля устроены так, что переход из одного состояния в другое не требует копирования данных в полях в новые места.

Далее в отчете вы можете найти внутренние асинхронные блоки:

type: `{async block@src/lib.rs:12:25: 20:10}`: 112 bytes, alignment: 8 bytes
    discriminant: 1 bytes
    variant `Unresumed`: 8 bytes
        upvar `._ref__stop_listener`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    variant `Suspend0`: 104 bytes
        upvar `._ref__stop_listener`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
        local `.__awaitee`: 96 bytes, type: Sleep
    variant `Returned`: 8 bytes
        upvar `._ref__stop_listener`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    variant `Panicked`: 8 bytes
        upvar `._ref__stop_listener`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    end padding: 7 bytes
type: `{async block@src/lib.rs:22:25: 28:10}`: 112 bytes, alignment: 8 bytes
    discriminant: 1 bytes
    variant `Unresumed`: 8 bytes
        upvar `._ref__result_channel`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    variant `Suspend0`: 104 bytes
        upvar `._ref__result_channel`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
        local `.__awaitee`: 96 bytes, type: Sleep
    variant `Returned`: 8 bytes
        upvar `._ref__result_channel`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    variant `Panicked`: 8 bytes
        upvar `._ref__result_channel`: 8 bytes, offset: 0 bytes, alignment: 8 bytes
    end padding: 7 bytes

Опять же, у каждого из них есть только одно await, поэтому у них есть только одно Suspend состояние, ожидающее экземпляра tokio::time::Sleep.

Другие вопросы по теме