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#[turbo_tasks::value_trait]
13pub trait Asset {
14 #[turbo_tasks::function]
16 fn content(self: Vc<Self>) -> Vc<AssetContent>;
17
18 #[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 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}