turbopack_core/chunk/
available_modules.rs1use anyhow::Result;
2use bincode::{Decode, Encode};
3use turbo_tasks::{
4 FxIndexSet, OperationVc, ReadRef, ResolvedVc, TryJoinIterExt, ValueToString, Vc,
5 trace::TraceRawVcs, turbofmt,
6};
7use turbo_tasks_hash::Xxh3Hash64Hasher;
8
9use crate::{
10 chunk::ChunkableModule,
11 module::Module,
12 module_graph::module_batch::{ChunkableModuleOrBatch, IdentStrings, ModuleBatch},
13};
14
15#[turbo_tasks::task_input]
16#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, TraceRawVcs, Encode, Decode)]
17pub enum AvailableModuleItem {
18 Module(ResolvedVc<Box<dyn ChunkableModule>>),
19 Batch(ResolvedVc<ModuleBatch>),
20 AsyncLoader(ResolvedVc<Box<dyn ChunkableModule>>),
21}
22
23impl AvailableModuleItem {
24 pub async fn ident_strings(&self) -> Result<IdentStrings> {
25 Ok(match self {
26 AvailableModuleItem::Module(module) => {
27 IdentStrings::Single(module.ident().to_string().owned().await?)
28 }
29 AvailableModuleItem::Batch(batch) => {
30 IdentStrings::Multiple(batch.ident_strings().await?)
31 }
32 AvailableModuleItem::AsyncLoader(module) => {
33 IdentStrings::Single(turbofmt!("async loader {}", module.ident()).await?)
34 }
35 })
36 }
37}
38
39impl From<ChunkableModuleOrBatch> for AvailableModuleItem {
40 fn from(value: ChunkableModuleOrBatch) -> Self {
41 match value {
42 ChunkableModuleOrBatch::Module(module) => AvailableModuleItem::Module(module),
43 ChunkableModuleOrBatch::Batch(batch) => AvailableModuleItem::Batch(batch),
44 ChunkableModuleOrBatch::None(id) => {
45 panic!("Cannot create AvailableModuleItem from None({})", id)
46 }
47 }
48 }
49}
50
51#[turbo_tasks::value(transparent)]
52#[derive(Debug, Clone)]
53pub struct AvailableModulesSet(
54 #[bincode(with = "turbo_bincode::indexset")] FxIndexSet<AvailableModuleItem>,
55);
56
57#[turbo_tasks::value]
61pub struct AvailableModules {
62 parent: Option<ResolvedVc<AvailableModules>>,
63 modules: OperationVc<AvailableModulesSet>,
64}
65
66#[turbo_tasks::value_impl]
67impl AvailableModules {
68 #[turbo_tasks::function]
69 pub fn new(modules: OperationVc<AvailableModulesSet>) -> Vc<Self> {
70 AvailableModules {
71 parent: None,
72 modules,
73 }
74 .cell()
75 }
76
77 #[turbo_tasks::function]
78 pub fn with_modules(
79 self: ResolvedVc<Self>,
80 modules: OperationVc<AvailableModulesSet>,
81 ) -> Result<Vc<Self>> {
82 Ok(AvailableModules {
83 parent: Some(self),
84 modules,
85 }
86 .cell())
87 }
88
89 #[turbo_tasks::function]
90 pub async fn hash(&self) -> Result<Vc<u64>> {
91 let mut hasher = Xxh3Hash64Hasher::new();
92 if let Some(parent) = self.parent {
93 hasher.write_value(parent.hash().await?);
94 } else {
95 hasher.write_value(0u64);
96 }
97 let item_idents = self
98 .modules
99 .connect()
100 .await?
101 .iter()
102 .map(async |&module| module.ident_strings().await)
103 .try_join()
104 .await?;
105 for idents in item_idents {
106 match idents {
107 IdentStrings::Single(ident) => hasher.write_value(ident),
108 IdentStrings::Multiple(idents) => {
109 for ident in &idents {
110 hasher.write_value(ident);
111 }
112 }
113 IdentStrings::None => {}
114 }
115 }
116 Ok(Vc::cell(hasher.finish()))
117 }
118
119 #[turbo_tasks::function]
120 pub async fn get(&self, item: AvailableModuleItem) -> Result<Vc<bool>> {
121 if self.modules.connect().await?.contains(&item) {
122 return Ok(Vc::cell(true));
123 };
124 if let Some(parent) = self.parent {
125 return Ok(parent.get(item));
126 }
127 Ok(Vc::cell(false))
128 }
129
130 #[turbo_tasks::function]
131 pub async fn snapshot(&self) -> Result<Vc<AvailableModulesSnapshot>> {
132 let modules = self.modules.connect().await?;
133 let parent = if let Some(parent) = self.parent {
134 Some(parent.snapshot().await?)
135 } else {
136 None
137 };
138
139 Ok(AvailableModulesSnapshot { parent, modules }.cell())
140 }
141}
142
143#[turbo_tasks::value(serialization = "skip")]
144#[derive(Debug, Clone)]
145pub struct AvailableModulesSnapshot {
146 parent: Option<ReadRef<AvailableModulesSnapshot>>,
147 modules: ReadRef<AvailableModulesSet>,
148}
149
150impl AvailableModulesSnapshot {
151 pub fn get(&self, item: AvailableModuleItem) -> bool {
152 self.modules.contains(&item) || self.parent.as_ref().is_some_and(|parent| parent.get(item))
153 }
154}