turbopack_ecmascript/chunk_list/
version.rs1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{FxIndexMap, ResolvedVc, TraitRef, TryJoinIterExt, Vc};
4use turbo_tasks_hash::{Xxh3Hash64Hasher, encode_base64};
5use turbopack_core::version::{
6 MergeableVersionedContent, Version, VersionedContent, VersionedContentMerger,
7};
8
9type VersionTraitRef = TraitRef<Box<dyn Version>>;
10
11#[turbo_tasks::value(serialization = "skip", shared)]
19pub struct ChunkListVersion {
20 #[turbo_tasks(trace_ignore)]
22 pub by_path: FxIndexMap<String, VersionTraitRef>,
23 #[turbo_tasks(trace_ignore)]
29 pub by_merger: FxIndexMap<ResolvedVc<Box<dyn VersionedContentMerger>>, VersionTraitRef>,
30}
31
32#[turbo_tasks::value_impl]
33impl Version for ChunkListVersion {
34 #[turbo_tasks::function]
35 async fn id(&self) -> Result<Vc<RcStr>> {
36 let by_path = {
37 let mut by_path = self
38 .by_path
39 .iter()
40 .map(|(path, version)| (path, TraitRef::cell(version.clone())))
41 .map(|(path, version)| async move {
42 let id = version.id().owned().await?;
43 Ok((path, id))
44 })
45 .try_join()
46 .await?;
47 by_path.sort();
48 by_path
49 };
50 let by_merger = {
51 let mut by_merger = self
52 .by_merger
53 .iter()
54 .map(|(_merger, version)| TraitRef::cell(version.clone()).id().owned())
55 .try_join()
56 .await?;
57 by_merger.sort();
58 by_merger
59 };
60 let mut hasher = Xxh3Hash64Hasher::new();
61 hasher.write_value(by_path.len());
62 for (path, id) in by_path {
63 hasher.write_value(path);
64 hasher.write_value(id);
65 }
66 hasher.write_value(by_merger.len());
67 for id in by_merger {
68 hasher.write_value(id);
69 }
70 let hash = hasher.finish();
71 let hash = encode_base64(hash);
72 Ok(Vc::cell(hash.into()))
73 }
74}
75
76pub async fn compute_chunk_list_version(
85 chunks_contents: &FxIndexMap<String, ResolvedVc<Box<dyn VersionedContent>>>,
86) -> Result<Vc<ChunkListVersion>> {
87 let mut by_merger = FxIndexMap::<_, Vec<_>>::default();
88 let mut by_path = FxIndexMap::<_, _>::default();
89
90 for (chunk_path, chunk_content) in chunks_contents {
91 if let Some(mergeable) =
92 ResolvedVc::try_sidecast::<Box<dyn MergeableVersionedContent>>(*chunk_content)
93 {
94 let merger = mergeable.get_merger().to_resolved().await?;
95 by_merger.entry(merger).or_default().push(*chunk_content);
96 } else {
97 by_path.insert(
98 chunk_path.clone(),
99 chunk_content.version().into_trait_ref().await?,
100 );
101 }
102 }
103
104 let by_merger = by_merger
105 .into_iter()
106 .map(|(merger, contents)| (merger, Vc::cell(contents)))
107 .map(async |(merger, contents)| {
108 Ok((
109 merger,
110 merger.merge(contents).version().into_trait_ref().await?,
111 ))
112 })
113 .try_join()
114 .await?
115 .into_iter()
116 .collect();
117
118 Ok(ChunkListVersion { by_path, by_merger }.cell())
119}