turbopack_core/
asset.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, Vc};
4use turbo_tasks_fs::{
5    FileContent, FileJsonContent, FileLinesContent, FileSystemPath, LinkContent, LinkType,
6};
7use turbo_tasks_hash::Xxh3Hash64Hasher;
8
9use crate::version::{VersionedAssetContent, VersionedContent};
10
11/// An asset. It also forms a graph when following [Asset::references].
12#[turbo_tasks::value_trait]
13pub trait Asset {
14    /// The content of the [Asset].
15    #[turbo_tasks::function]
16    fn content(self: Vc<Self>) -> Vc<AssetContent>;
17
18    /// The content of the [Asset] alongside its version.
19    #[turbo_tasks::function]
20    fn versioned_content(self: Vc<Self>) -> Result<Vc<Box<dyn VersionedContent>>> {
21        Ok(Vc::upcast(VersionedAssetContent::new(self.content())))
22    }
23}
24
25#[turbo_tasks::value(shared)]
26#[derive(Clone)]
27pub enum AssetContent {
28    File(ResolvedVc<FileContent>),
29    // for the relative link, the target is raw value read from the link
30    // for the absolute link, the target is stripped of the root path while reading
31    // See [LinkContent::Link] for more details.
32    Redirect { target: RcStr, link_type: LinkType },
33}
34
35#[turbo_tasks::value_impl]
36impl AssetContent {
37    #[turbo_tasks::function]
38    pub fn file(file: ResolvedVc<FileContent>) -> Result<Vc<Self>> {
39        Ok(AssetContent::File(file).cell())
40    }
41
42    #[turbo_tasks::function]
43    pub async fn parse_json(self: Vc<Self>) -> Result<Vc<FileJsonContent>> {
44        let this = self.await?;
45        match &*this {
46            AssetContent::File(content) => Ok(content.parse_json()),
47            AssetContent::Redirect { .. } => Ok(FileJsonContent::unparsable(rcstr!(
48                "a redirect can't be parsed as json"
49            ))
50            .cell()),
51        }
52    }
53
54    #[turbo_tasks::function]
55    pub async fn file_content(self: Vc<Self>) -> Result<Vc<FileContent>> {
56        let this = self.await?;
57        match &*this {
58            AssetContent::File(content) => Ok(**content),
59            AssetContent::Redirect { .. } => Ok(FileContent::NotFound.cell()),
60        }
61    }
62
63    #[turbo_tasks::function]
64    pub async fn lines(self: Vc<Self>) -> Result<Vc<FileLinesContent>> {
65        let this = self.await?;
66        match &*this {
67            AssetContent::File(content) => Ok(content.lines()),
68            AssetContent::Redirect { .. } => Ok(FileLinesContent::Unparsable.cell()),
69        }
70    }
71
72    #[turbo_tasks::function]
73    pub async fn len(self: Vc<Self>) -> Result<Vc<Option<u64>>> {
74        let this = self.await?;
75        match &*this {
76            AssetContent::File(content) => Ok(content.len()),
77            AssetContent::Redirect { .. } => Ok(Vc::cell(None)),
78        }
79    }
80
81    #[turbo_tasks::function]
82    pub async fn parse_json_with_comments(self: Vc<Self>) -> Result<Vc<FileJsonContent>> {
83        let this = self.await?;
84        match &*this {
85            AssetContent::File(content) => Ok(content.parse_json_with_comments()),
86            AssetContent::Redirect { .. } => Ok(FileJsonContent::unparsable(rcstr!(
87                "a redirect can't be parsed as json"
88            ))
89            .cell()),
90        }
91    }
92
93    #[turbo_tasks::function]
94    pub async fn write(self: Vc<Self>, path: FileSystemPath) -> Result<()> {
95        let this = self.await?;
96        match &*this {
97            AssetContent::File(file) => {
98                path.write(**file).as_side_effect().await?;
99            }
100            AssetContent::Redirect { target, link_type } => {
101                path.write_link(
102                    LinkContent::Link {
103                        target: target.clone(),
104                        link_type: *link_type,
105                    }
106                    .cell(),
107                )
108                .as_side_effect()
109                .await?;
110            }
111        }
112        Ok(())
113    }
114
115    #[turbo_tasks::function]
116    pub async fn hash(&self) -> Result<Vc<u64>> {
117        match self {
118            AssetContent::File(content) => Ok(content.hash()),
119            AssetContent::Redirect { target, link_type } => {
120                use turbo_tasks_hash::DeterministicHash;
121                let mut hasher = Xxh3Hash64Hasher::new();
122                target.deterministic_hash(&mut hasher);
123                link_type.deterministic_hash(&mut hasher);
124                Ok(Vc::cell(hasher.finish()))
125            }
126        }
127    }
128}