Skip to main content

turbopack_core/chunk/
availability_info.rs

1use anyhow::Result;
2use bincode::{Decode, Encode};
3use bitfield::bitfield;
4use turbo_rcstr::RcStr;
5use turbo_tasks::ResolvedVc;
6
7use crate::{
8    chunk::available_chunk_groups::AvailableChunkGroups,
9    module::Modules,
10    module_graph::{
11        ModuleGraph, chunk_group_info::ChunkGroupKey, module_batch::ChunkableModuleOrBatch,
12    },
13};
14
15bitfield! {
16    #[turbo_tasks::task_input]
17    #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Encode, Decode)]
18    pub struct AvailabilityFlags(u8);
19    impl Debug;
20    pub is_in_async_module, set_is_in_async_module: 0;
21}
22
23#[turbo_tasks::task_input]
24#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug, Encode, Decode)]
25pub struct AvailabilityInfo {
26    flags: AvailabilityFlags,
27    /// Chunk groups whose contents are already available.
28    available_chunk_groups: Option<ResolvedVc<AvailableChunkGroups>>,
29    /// The root ChunkGroup::Entry
30    entry_group: Option<ResolvedVc<Modules>>,
31}
32
33impl AvailabilityInfo {
34    pub fn root() -> Self {
35        Self {
36            flags: AvailabilityFlags::default(),
37            available_chunk_groups: None,
38            entry_group: None,
39        }
40    }
41
42    pub fn available_chunk_groups(&self) -> Option<ResolvedVc<AvailableChunkGroups>> {
43        self.available_chunk_groups
44    }
45
46    pub async fn with_chunk_group(
47        self,
48        module_graph: ResolvedVc<ModuleGraph>,
49        chunk_group: ChunkGroupKey,
50    ) -> Result<Self> {
51        let chunk_group = module_graph
52            .chunk_group_info()
53            .get_index_of(chunk_group)
54            .await? as u32;
55        Ok(Self {
56            flags: self.flags,
57            available_chunk_groups: Some(
58                if let Some(available_chunk_groups) = self.available_chunk_groups {
59                    available_chunk_groups
60                        .with_chunk_group(*module_graph, chunk_group)
61                        .to_resolved()
62                        .await?
63                } else {
64                    AvailableChunkGroups::new(*module_graph, chunk_group)
65                        .to_resolved()
66                        .await?
67                },
68            ),
69            entry_group: self.entry_group,
70        })
71    }
72
73    /// Whether the module or module batch is already part of one of the available chunk groups.
74    pub async fn is_available(
75        &self,
76        module_graph: ResolvedVc<ModuleGraph>,
77        item: ChunkableModuleOrBatch,
78    ) -> Result<bool> {
79        let Some(available_chunk_groups) = self.available_chunk_groups else {
80            return Ok(false);
81        };
82        let available_chunk_groups = available_chunk_groups.await?;
83        let chunk_group_info = module_graph.chunk_group_info().await?;
84        let module = match item {
85            ChunkableModuleOrBatch::Module(module) => ResolvedVc::upcast(module),
86            // All modules of a batch have the same chunk groups, so the first one is
87            // representative.
88            ChunkableModuleOrBatch::Batch(batch) => match batch.await?.modules.first() {
89                Some(&module) => ResolvedVc::upcast(module),
90                None => return Ok(false),
91            },
92            ChunkableModuleOrBatch::None(_) => return Ok(false),
93        };
94        Ok(chunk_group_info
95            .module_chunk_groups
96            .await?
97            .get(&module)
98            .is_some_and(|groups| {
99                !groups.is_disjoint(available_chunk_groups.chunk_groups(module_graph))
100            }))
101    }
102
103    pub fn in_async_module(self) -> Self {
104        let mut flags = self.flags;
105        flags.set_is_in_async_module(true);
106        Self {
107            flags,
108            available_chunk_groups: self.available_chunk_groups,
109            entry_group: self.entry_group,
110        }
111    }
112
113    pub fn is_in_async_module(&self) -> bool {
114        self.flags.is_in_async_module()
115    }
116
117    pub fn with_entry_group(self, entry_group: ResolvedVc<Modules>) -> Self {
118        Self {
119            flags: self.flags,
120            available_chunk_groups: self.available_chunk_groups,
121            entry_group: Some(entry_group),
122        }
123    }
124
125    pub fn entry_group(&self) -> Option<ResolvedVc<Modules>> {
126        self.entry_group
127    }
128
129    pub async fn ident(&self) -> Result<Option<RcStr>> {
130        Ok(
131            if let Some(available_chunk_groups) = self.available_chunk_groups {
132                Some(available_chunk_groups.hash().await?.to_string().into())
133            } else {
134                None
135            },
136        )
137    }
138}