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