turbopack_core/chunk/
available_modules.rs

1use anyhow::Result;
2use turbo_tasks::{FxIndexSet, ReadRef, ResolvedVc, TryJoinIterExt, Vc};
3use turbo_tasks_hash::Xxh3Hash64Hasher;
4
5use crate::module_graph::module_batch::{ChunkableModuleOrBatch, IdentStrings};
6
7#[turbo_tasks::value(transparent)]
8#[derive(Debug, Clone)]
9pub struct AvailableModulesSet(FxIndexSet<ChunkableModuleOrBatch>);
10
11/// Allows to gather information about which assets are already available.
12/// Adding more roots will form a linked list like structure to allow caching
13/// `include` queries.
14#[turbo_tasks::value]
15pub struct AvailableModules {
16    parent: Option<ResolvedVc<AvailableModules>>,
17    modules: ResolvedVc<AvailableModulesSet>,
18}
19
20#[turbo_tasks::value_impl]
21impl AvailableModules {
22    #[turbo_tasks::function]
23    pub fn new(modules: ResolvedVc<AvailableModulesSet>) -> Vc<Self> {
24        AvailableModules {
25            parent: None,
26            modules,
27        }
28        .cell()
29    }
30
31    #[turbo_tasks::function]
32    pub async fn with_modules(
33        self: ResolvedVc<Self>,
34        modules: ResolvedVc<AvailableModulesSet>,
35    ) -> Result<Vc<Self>> {
36        Ok(AvailableModules {
37            parent: Some(self),
38            modules,
39        }
40        .cell())
41    }
42
43    #[turbo_tasks::function]
44    pub async fn hash(&self) -> Result<Vc<u64>> {
45        let mut hasher = Xxh3Hash64Hasher::new();
46        if let Some(parent) = self.parent {
47            hasher.write_value(parent.hash().await?);
48        } else {
49            hasher.write_value(0u64);
50        }
51        let item_idents = self
52            .modules
53            .await?
54            .iter()
55            .map(|&module| module.ident_strings())
56            .try_join()
57            .await?;
58        for idents in item_idents {
59            match idents {
60                IdentStrings::Single(ident) => hasher.write_value(ident),
61                IdentStrings::Multiple(idents) => {
62                    for ident in idents {
63                        hasher.write_value(ident);
64                    }
65                }
66                IdentStrings::None => {}
67            }
68        }
69        Ok(Vc::cell(hasher.finish()))
70    }
71
72    #[turbo_tasks::function]
73    pub async fn get(&self, module_or_batch: ChunkableModuleOrBatch) -> Result<Vc<bool>> {
74        if self.modules.await?.contains(&module_or_batch) {
75            return Ok(Vc::cell(true));
76        };
77        if let Some(parent) = self.parent {
78            return Ok(parent.get(module_or_batch));
79        }
80        Ok(Vc::cell(false))
81    }
82
83    #[turbo_tasks::function]
84    pub async fn snapshot(&self) -> Result<Vc<AvailableModulesSnapshot>> {
85        let modules = self.modules.await?;
86        let parent = if let Some(parent) = self.parent {
87            Some(parent.snapshot().await?)
88        } else {
89            None
90        };
91
92        Ok(AvailableModulesSnapshot { parent, modules }.cell())
93    }
94}
95
96#[turbo_tasks::value(serialization = "none")]
97#[derive(Debug, Clone)]
98pub struct AvailableModulesSnapshot {
99    parent: Option<ReadRef<AvailableModulesSnapshot>>,
100    modules: ReadRef<AvailableModulesSet>,
101}
102
103impl AvailableModulesSnapshot {
104    pub fn get(&self, module_or_batch: ChunkableModuleOrBatch) -> bool {
105        self.modules.contains(&module_or_batch)
106            || self
107                .parent
108                .as_ref()
109                .is_some_and(|parent| parent.get(module_or_batch))
110    }
111}