1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{ResolvedVc, ValueToString, Vc, turbobail};
4
5use crate::{FileContent, FileMeta, FileSystem, FileSystemPath, LinkContent, RawDirectoryContent};
6
7#[derive(ValueToString)]
12#[value_to_string("{root_fs}-with-{child_fs}")]
13#[turbo_tasks::value]
14pub struct AttachedFileSystem {
15 root_fs: ResolvedVc<Box<dyn FileSystem>>,
16 child_path: RcStr,
19 child_fs: ResolvedVc<Box<dyn FileSystem>>,
20}
21
22#[turbo_tasks::value_impl]
23impl AttachedFileSystem {
24 #[turbo_tasks::function]
27 pub async fn new(
28 child_path: FileSystemPath,
29 child_fs: ResolvedVc<Box<dyn FileSystem>>,
30 ) -> Result<Vc<Self>> {
31 Ok(AttachedFileSystem {
32 root_fs: child_path.fs,
33 child_path: child_path.path.clone(),
34 child_fs,
35 }
36 .cell())
37 }
38
39 #[turbo_tasks::function]
42 async fn child_path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
43 Ok(self.root().await?.join(&self.await?.child_path)?.cell())
44 }
45
46 #[turbo_tasks::function]
49 pub async fn get_inner_fs_path(
50 self: ResolvedVc<Self>,
51 path: FileSystemPath,
52 ) -> Result<Vc<FileSystemPath>> {
53 let this = self.await?;
54 let self_fs: ResolvedVc<Box<dyn FileSystem>> = ResolvedVc::upcast(self);
55
56 if path.fs != self_fs {
57 turbobail!(
58 "path fs does not match (expected {self_fs}, got {})",
59 path.fs
60 )
61 }
62
63 let child_path = self.child_path().await?;
64 Ok(if let Some(inner_path) = child_path.get_path_to(&path) {
65 this.child_fs.root().await?.join(inner_path)?.cell()
66 } else {
67 this.root_fs.root().await?.join(&path.path)?.cell()
68 })
69 }
70}
71
72#[turbo_tasks::value_impl]
73impl FileSystem for AttachedFileSystem {
74 #[turbo_tasks::function(fs)]
75 async fn read(self: Vc<Self>, path: FileSystemPath) -> Result<Vc<FileContent>> {
76 Ok(self.get_inner_fs_path(path).await?.read())
77 }
78
79 #[turbo_tasks::function(fs)]
80 async fn read_link(self: Vc<Self>, path: FileSystemPath) -> Result<Vc<LinkContent>> {
81 Ok(self.get_inner_fs_path(path).await?.read_link())
82 }
83
84 #[turbo_tasks::function(fs)]
85 async fn raw_read_dir(self: Vc<Self>, path: FileSystemPath) -> Result<Vc<RawDirectoryContent>> {
86 Ok(self.get_inner_fs_path(path).await?.raw_read_dir())
87 }
88
89 #[turbo_tasks::function(fs)]
90 async fn write(
91 self: Vc<Self>,
92 path: FileSystemPath,
93 content: Vc<FileContent>,
94 ) -> Result<Vc<()>> {
95 Ok(self.get_inner_fs_path(path).await?.write(content))
96 }
97
98 #[turbo_tasks::function(fs)]
99 async fn write_link(
100 self: Vc<Self>,
101 path: FileSystemPath,
102 target: Vc<LinkContent>,
103 ) -> Result<Vc<()>> {
104 Ok(self
105 .get_inner_fs_path(path)
106 .await?
107 .write_symbolic_link_dir(target))
108 }
109
110 #[turbo_tasks::function]
111 async fn metadata(self: Vc<Self>, path: FileSystemPath) -> Result<Vc<FileMeta>> {
112 Ok(self.get_inner_fs_path(path).await?.metadata())
113 }
114}