turbopack_core/chunk/
available_modules.rs1use anyhow::Result;
2use bincode::{Decode, Encode};
3use turbo_tasks::{
4 FxIndexSet, NonLocalValue, ReadRef, ResolvedVc, TaskInput, TryJoinIterExt, ValueToString, Vc,
5 trace::TraceRawVcs,
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) => IdentStrings::Single(
34 format!("async loader {}", module.ident().to_string().await?).into(),
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: ResolvedVc<AvailableModulesSet>,
65}
66
67#[turbo_tasks::value_impl]
68impl AvailableModules {
69 #[turbo_tasks::function]
70 pub fn new(modules: ResolvedVc<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: ResolvedVc<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 .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.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.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 = "none")]
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}