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::{HashAlgorithm, 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 #[turbo_tasks::function]
26 fn content_hash(self: Vc<Self>, algorithm: HashAlgorithm) -> Vc<Option<RcStr>> {
27 self.content().content_hash(algorithm)
28 }
29}
30
31#[turbo_tasks::value(shared)]
32#[derive(Clone)]
33pub enum AssetContent {
34 File(ResolvedVc<FileContent>),
35 Redirect { target: RcStr, link_type: LinkType },
39}
40
41#[turbo_tasks::value_impl]
42impl AssetContent {
43 #[turbo_tasks::function]
44 pub fn file(file: ResolvedVc<FileContent>) -> Result<Vc<Self>> {
45 Ok(AssetContent::File(file).cell())
46 }
47
48 #[turbo_tasks::function]
49 pub fn parse_json(&self) -> Vc<FileJsonContent> {
50 match self {
51 AssetContent::File(content) => content.parse_json(),
52 AssetContent::Redirect { .. } => {
53 FileJsonContent::unparsable(rcstr!("a redirect can't be parsed as json")).cell()
54 }
55 }
56 }
57
58 #[turbo_tasks::function]
59 pub fn file_content(&self) -> Vc<FileContent> {
60 match self {
61 AssetContent::File(content) => **content,
62 AssetContent::Redirect { .. } => FileContent::NotFound.cell(),
63 }
64 }
65
66 #[turbo_tasks::function]
67 pub fn lines(&self) -> Vc<FileLinesContent> {
68 match self {
69 AssetContent::File(content) => content.lines(),
70 AssetContent::Redirect { .. } => FileLinesContent::Unparsable.cell(),
71 }
72 }
73
74 #[turbo_tasks::function]
75 pub fn len(&self) -> Vc<Option<u64>> {
76 match self {
77 AssetContent::File(content) => content.len(),
78 AssetContent::Redirect { .. } => Vc::cell(None),
79 }
80 }
81
82 #[turbo_tasks::function]
83 pub fn parse_json_with_comments(&self) -> Vc<FileJsonContent> {
84 match self {
85 AssetContent::File(content) => content.parse_json_with_comments(),
86 AssetContent::Redirect { .. } => {
87 FileJsonContent::unparsable(rcstr!("a redirect can't be parsed as json")).cell()
88 }
89 }
90 }
91
92 #[turbo_tasks::function]
93 pub async fn write(&self, path: FileSystemPath) -> Result<()> {
94 match self {
95 AssetContent::File(file) => {
96 path.write(**file).as_side_effect().await?;
97 }
98 AssetContent::Redirect { target, link_type } => {
99 path.write_symbolic_link_dir(
100 LinkContent::Link {
101 target: target.clone(),
102 link_type: *link_type,
103 }
104 .cell(),
105 )
106 .as_side_effect()
107 .await?;
108 }
109 }
110 Ok(())
111 }
112
113 #[turbo_tasks::function]
114 pub async fn hash(&self) -> Result<Vc<u64>> {
115 match self {
116 AssetContent::File(content) => Ok(content.hash()),
117 AssetContent::Redirect { target, link_type } => {
118 use turbo_tasks_hash::DeterministicHash;
119 let mut hasher = Xxh3Hash64Hasher::new();
120 target.deterministic_hash(&mut hasher);
121 link_type.deterministic_hash(&mut hasher);
122 Ok(Vc::cell(hasher.finish()))
123 }
124 }
125 }
126
127 #[turbo_tasks::function]
130 pub async fn content_hash(&self, algorithm: HashAlgorithm) -> Result<Vc<Option<RcStr>>> {
131 match self {
132 AssetContent::File(content) => Ok(content.content_hash(algorithm)),
133 AssetContent::Redirect { .. } => Ok(Vc::cell(None)),
134 }
135 }
136}