@wasm-oj/server 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/THIRD_PARTY_NOTICES.md +302 -0
  4. package/crates/runtime-core/Cargo.lock +5099 -0
  5. package/crates/runtime-core/Cargo.toml +66 -0
  6. package/crates/runtime-core/README.md +47 -0
  7. package/crates/runtime-core/src/bin/wasm-oj-compiler.rs +418 -0
  8. package/crates/runtime-core/src/bin/wasm-oj-runner.rs +294 -0
  9. package/crates/runtime-core/src/capabilities.rs +118 -0
  10. package/crates/runtime-core/src/compiler.rs +658 -0
  11. package/crates/runtime-core/src/contract.rs +5 -0
  12. package/crates/runtime-core/src/deterministic.rs +1051 -0
  13. package/crates/runtime-core/src/error.rs +58 -0
  14. package/crates/runtime-core/src/filesystem.rs +547 -0
  15. package/crates/runtime-core/src/filesystem_quota.rs +167 -0
  16. package/crates/runtime-core/src/go_compiler_session.rs +297 -0
  17. package/crates/runtime-core/src/interactive.rs +1019 -0
  18. package/crates/runtime-core/src/judge_package.rs +1539 -0
  19. package/crates/runtime-core/src/lib.rs +98 -0
  20. package/crates/runtime-core/src/memory.rs +84 -0
  21. package/crates/runtime-core/src/meter.rs +549 -0
  22. package/crates/runtime-core/src/module_imports.rs +149 -0
  23. package/crates/runtime-core/src/module_policy.rs +714 -0
  24. package/crates/runtime-core/src/output.rs +204 -0
  25. package/crates/runtime-core/src/run/mod.rs +208 -0
  26. package/crates/runtime-core/src/run/native.rs +260 -0
  27. package/crates/runtime-core/src/run/web.rs +229 -0
  28. package/crates/runtime-core/src/run/web_runtime.rs +109 -0
  29. package/crates/runtime-core/src/types.rs +268 -0
  30. package/crates/runtime-core/src/web.rs +83 -0
  31. package/dist/chunks/go-toolchain-Dbt-lp2L.js +426 -0
  32. package/dist/chunks/java-toolchain-DajoRCHu.js +44 -0
  33. package/dist/chunks/python-toolchain-Dx834o2A.js +4 -0
  34. package/dist/chunks/rust-toolchain-CJ3sMxPE.js +252 -0
  35. package/dist/chunks/toolchains-C6KuA1yM.js +224 -0
  36. package/dist/go-stage.mjs +193 -0
  37. package/dist/index.d.ts +221 -0
  38. package/dist/index.js +4393 -0
  39. package/dist/java-stage.mjs +111 -0
  40. package/dist/python-stage.mjs +90 -0
  41. package/dist/rustc-stage.mjs +301 -0
  42. package/dist/server-build-stage.mjs +2564 -0
  43. package/dist/server-runner-stage.mjs +155 -0
  44. package/licenses/fflate-MIT.txt +21 -0
  45. package/licenses/runtime-core-dependencies.html +6253 -0
  46. package/licenses/runtime-core-dependencies.json +3041 -0
  47. package/licenses/wasmer-sdk-MIT.txt +21 -0
  48. package/licenses/wasmer-sdk-dependencies.html +6901 -0
  49. package/licenses/wasmer-sdk-dependencies.json +3013 -0
  50. package/package.json +70 -0
  51. package/rust-toolchain.toml +5 -0
  52. package/testdata/wojjdg02-v2-text.hex +1 -0
  53. package/vendor/shared-buffer/Cargo.toml +22 -0
  54. package/vendor/shared-buffer/LICENSE_APACHE.md +176 -0
  55. package/vendor/shared-buffer/LICENSE_MIT.md +25 -0
  56. package/vendor/shared-buffer/README.md +34 -0
  57. package/vendor/shared-buffer/src/lib.rs +58 -0
  58. package/vendor/shared-buffer/src/mmap.rs +250 -0
  59. package/vendor/shared-buffer/src/owned.rs +389 -0
  60. package/vendor/virtual-fs/Cargo.toml +181 -0
  61. package/vendor/virtual-fs/LICENSE +25 -0
  62. package/vendor/virtual-fs/src/arc_box_file.rs +142 -0
  63. package/vendor/virtual-fs/src/arc_file.rs +182 -0
  64. package/vendor/virtual-fs/src/arc_fs.rs +68 -0
  65. package/vendor/virtual-fs/src/buffer_file.rs +103 -0
  66. package/vendor/virtual-fs/src/builder.rs +232 -0
  67. package/vendor/virtual-fs/src/combine_file.rs +101 -0
  68. package/vendor/virtual-fs/src/cow_file.rs +345 -0
  69. package/vendor/virtual-fs/src/dual_write_file.rs +113 -0
  70. package/vendor/virtual-fs/src/empty_fs.rs +81 -0
  71. package/vendor/virtual-fs/src/filesystems.rs +108 -0
  72. package/vendor/virtual-fs/src/host_fs.rs +1390 -0
  73. package/vendor/virtual-fs/src/lib.rs +782 -0
  74. package/vendor/virtual-fs/src/limiter.rs +252 -0
  75. package/vendor/virtual-fs/src/mem_fs/file.rs +1799 -0
  76. package/vendor/virtual-fs/src/mem_fs/file_opener.rs +941 -0
  77. package/vendor/virtual-fs/src/mem_fs/filesystem.rs +2134 -0
  78. package/vendor/virtual-fs/src/mem_fs/mod.rs +245 -0
  79. package/vendor/virtual-fs/src/mem_fs/offloaded_file.rs +474 -0
  80. package/vendor/virtual-fs/src/mem_fs/stdio.rs +318 -0
  81. package/vendor/virtual-fs/src/mount_fs.rs +2225 -0
  82. package/vendor/virtual-fs/src/null_file.rs +87 -0
  83. package/vendor/virtual-fs/src/ops.rs +364 -0
  84. package/vendor/virtual-fs/src/overlay_fs.rs +2216 -0
  85. package/vendor/virtual-fs/src/passthru_fs.rs +119 -0
  86. package/vendor/virtual-fs/src/pipe.rs +603 -0
  87. package/vendor/virtual-fs/src/random_file.rs +88 -0
  88. package/vendor/virtual-fs/src/special_file.rs +108 -0
  89. package/vendor/virtual-fs/src/static_file.rs +133 -0
  90. package/vendor/virtual-fs/src/static_fs.rs +460 -0
  91. package/vendor/virtual-fs/src/tmp_fs.rs +95 -0
  92. package/vendor/virtual-fs/src/trace_fs.rs +258 -0
  93. package/vendor/virtual-fs/src/webc_volume_fs.rs +829 -0
  94. package/vendor/virtual-fs/src/zero_file.rs +90 -0
@@ -0,0 +1,460 @@
1
+ use anyhow::anyhow;
2
+ use futures::future::BoxFuture;
3
+ use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
4
+
5
+ use std::convert::TryInto;
6
+ use std::io::{self, Error as IoError, ErrorKind as IoErrorKind, SeekFrom};
7
+ use std::path::Path;
8
+ use std::path::PathBuf;
9
+ use std::pin::Pin;
10
+ use std::sync::Arc;
11
+ use std::task::{Context, Poll};
12
+
13
+ use crate::mem_fs::FileSystem as MemFileSystem;
14
+ use crate::{
15
+ FileOpener, FileSystem, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir, VirtualFile,
16
+ };
17
+ use indexmap::IndexMap;
18
+ use webc::v1::{FsEntry, FsEntryType, OwnedFsEntryFile};
19
+
20
+ /// Custom file system wrapper to map requested file paths
21
+ #[derive(Debug)]
22
+ pub struct StaticFileSystem {
23
+ pub package: String,
24
+ pub volumes: Arc<IndexMap<String, webc::v1::Volume<'static>>>,
25
+ pub memory: Arc<MemFileSystem>,
26
+ }
27
+
28
+ impl StaticFileSystem {
29
+ pub fn init(bytes: &'static [u8], package: &str) -> Option<Self> {
30
+ let volumes = Arc::new(webc::v1::WebC::parse_volumes_from_fileblock(bytes).ok()?);
31
+ let fs = Self {
32
+ package: package.to_string(),
33
+ volumes: volumes.clone(),
34
+ memory: Arc::new(MemFileSystem::default()),
35
+ };
36
+ let volume_names = fs.volumes.keys().cloned().collect::<Vec<_>>();
37
+ for volume_name in volume_names {
38
+ let directories = volumes.get(&volume_name).unwrap().list_directories();
39
+ for directory in directories {
40
+ let _ = fs.create_dir(Path::new(&directory));
41
+ }
42
+ }
43
+ Some(fs)
44
+ }
45
+ }
46
+
47
+ /// Custom file opener, returns a WebCFile
48
+ impl FileOpener for StaticFileSystem {
49
+ fn open(
50
+ &self,
51
+ path: &Path,
52
+ _conf: &OpenOptionsConfig,
53
+ ) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> {
54
+ match get_volume_name_opt(path) {
55
+ Some(volume) => {
56
+ let file = (*self.volumes)
57
+ .get(&volume)
58
+ .ok_or(FsError::EntryNotFound)?
59
+ .get_file_entry(path.to_string_lossy().as_ref())
60
+ .map_err(|_e| FsError::EntryNotFound)?;
61
+
62
+ Ok(Box::new(WebCFile {
63
+ package: self.package.clone(),
64
+ volume,
65
+ volumes: self.volumes.clone(),
66
+ path: path.to_path_buf(),
67
+ entry: file,
68
+ cursor: 0,
69
+ }))
70
+ }
71
+ None => {
72
+ for (volume, v) in self.volumes.iter() {
73
+ let entry = match v.get_file_entry(path.to_string_lossy().as_ref()) {
74
+ Ok(s) => s,
75
+ Err(_) => continue, // error
76
+ };
77
+
78
+ return Ok(Box::new(WebCFile {
79
+ package: self.package.clone(),
80
+ volume: volume.clone(),
81
+ volumes: self.volumes.clone(),
82
+ path: path.to_path_buf(),
83
+ entry,
84
+ cursor: 0,
85
+ }));
86
+ }
87
+ self.memory.new_open_options().open(path)
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ #[derive(Debug)]
94
+ pub struct WebCFile {
95
+ pub volumes: Arc<IndexMap<String, webc::v1::Volume<'static>>>,
96
+ pub package: String,
97
+ pub volume: String,
98
+ pub path: PathBuf,
99
+ pub entry: OwnedFsEntryFile,
100
+ pub cursor: u64,
101
+ }
102
+
103
+ #[async_trait::async_trait]
104
+ impl VirtualFile for WebCFile {
105
+ fn last_accessed(&self) -> u64 {
106
+ 0
107
+ }
108
+ fn last_modified(&self) -> u64 {
109
+ 0
110
+ }
111
+ fn created_time(&self) -> u64 {
112
+ 0
113
+ }
114
+ fn size(&self) -> u64 {
115
+ self.entry.get_len()
116
+ }
117
+ fn set_len(&mut self, _new_size: u64) -> crate::Result<()> {
118
+ Ok(())
119
+ }
120
+ fn unlink(&mut self) -> Result<(), FsError> {
121
+ Ok(())
122
+ }
123
+ fn poll_read_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
124
+ let remaining = self.entry.get_len() - self.cursor;
125
+ Poll::Ready(Ok(remaining as usize))
126
+ }
127
+ fn poll_write_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
128
+ Poll::Ready(Ok(0))
129
+ }
130
+ }
131
+
132
+ impl AsyncRead for WebCFile {
133
+ fn poll_read(
134
+ self: Pin<&mut Self>,
135
+ _cx: &mut Context<'_>,
136
+ buf: &mut tokio::io::ReadBuf<'_>,
137
+ ) -> Poll<io::Result<()>> {
138
+ let this = self.get_mut();
139
+ let bytes = this
140
+ .volumes
141
+ .get(&this.volume)
142
+ .ok_or_else(|| {
143
+ IoError::new(
144
+ IoErrorKind::NotFound,
145
+ anyhow!("Unknown volume {:?}", this.volume),
146
+ )
147
+ })?
148
+ .get_file_bytes(&this.entry)
149
+ .map_err(|e| IoError::new(IoErrorKind::NotFound, e))?;
150
+
151
+ let cursor: usize = this.cursor.try_into().unwrap_or(u32::MAX as usize);
152
+ let start = cursor.min(bytes.len());
153
+ let bytes = &bytes[start..];
154
+ let bytes_read = bytes.len().min(buf.remaining());
155
+
156
+ if bytes_read > 0 {
157
+ buf.put_slice(&bytes[..bytes_read]);
158
+ this.cursor = this.cursor.saturating_add(bytes_read as u64);
159
+ }
160
+ Poll::Ready(Ok(()))
161
+ }
162
+ }
163
+
164
+ // WebC file is not writable, the FileOpener will return a MemoryFile for writing instead
165
+ // This code should never be executed (since writes are redirected to memory instead).
166
+ impl AsyncWrite for WebCFile {
167
+ fn poll_write(
168
+ self: Pin<&mut Self>,
169
+ _cx: &mut Context<'_>,
170
+ buf: &[u8],
171
+ ) -> Poll<io::Result<usize>> {
172
+ Poll::Ready(Ok(buf.len()))
173
+ }
174
+ fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
175
+ Poll::Ready(Ok(()))
176
+ }
177
+ fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
178
+ Poll::Ready(Ok(()))
179
+ }
180
+ }
181
+
182
+ impl AsyncSeek for WebCFile {
183
+ fn start_seek(mut self: Pin<&mut Self>, pos: io::SeekFrom) -> io::Result<()> {
184
+ let self_size = self.size();
185
+ match pos {
186
+ SeekFrom::Start(s) => {
187
+ self.cursor = s.min(self_size);
188
+ }
189
+ SeekFrom::End(e) => {
190
+ let self_size_i64 = self_size.try_into().unwrap_or(i64::MAX);
191
+ self.cursor = ((self_size_i64).saturating_add(e))
192
+ .min(self_size_i64)
193
+ .try_into()
194
+ .unwrap_or(i64::MAX as u64);
195
+ }
196
+ SeekFrom::Current(c) => {
197
+ self.cursor = (self
198
+ .cursor
199
+ .saturating_add(c.try_into().unwrap_or(i64::MAX as u64)))
200
+ .min(self_size);
201
+ }
202
+ }
203
+ Ok(())
204
+ }
205
+ fn poll_complete(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
206
+ Poll::Ready(Ok(self.cursor))
207
+ }
208
+ }
209
+
210
+ fn get_volume_name_opt<P: AsRef<Path>>(path: P) -> Option<String> {
211
+ use std::path::Component::Normal;
212
+ if let Some(Normal(n)) = path.as_ref().components().next()
213
+ && let Some(s) = n.to_str()
214
+ && s.ends_with(':')
215
+ {
216
+ return Some(s.replace(':', ""));
217
+ }
218
+ None
219
+ }
220
+
221
+ fn transform_into_read_dir(path: &Path, fs_entries: &[FsEntry<'_>]) -> crate::ReadDir {
222
+ let entries = fs_entries
223
+ .iter()
224
+ .map(|e| crate::DirEntry {
225
+ path: path.join(&*e.text),
226
+ metadata: Ok(crate::Metadata {
227
+ ft: translate_file_type(e.fs_type),
228
+ accessed: 0,
229
+ created: 0,
230
+ modified: 0,
231
+ len: e.get_len(),
232
+ }),
233
+ })
234
+ .collect();
235
+
236
+ crate::ReadDir::new(entries)
237
+ }
238
+
239
+ impl FileSystem for StaticFileSystem {
240
+ fn readlink(&self, path: &Path) -> crate::Result<PathBuf> {
241
+ let path = normalizes_path(path);
242
+ if self
243
+ .volumes
244
+ .values()
245
+ .find_map(|v| v.get_file_entry(&path).ok())
246
+ .is_some()
247
+ {
248
+ Err(FsError::InvalidInput)
249
+ } else {
250
+ self.memory.readlink(Path::new(&path))
251
+ }
252
+ }
253
+
254
+ fn read_dir(&self, path: &Path) -> Result<ReadDir, FsError> {
255
+ let path = normalizes_path(path);
256
+ for volume in self.volumes.values() {
257
+ let read_dir_result = volume
258
+ .read_dir(&path)
259
+ .map(|o| transform_into_read_dir(Path::new(&path), o.as_ref()))
260
+ .map_err(|_| FsError::EntryNotFound);
261
+
262
+ match read_dir_result {
263
+ Ok(o) => {
264
+ return Ok(o);
265
+ }
266
+ Err(_) => {
267
+ continue;
268
+ }
269
+ }
270
+ }
271
+
272
+ self.memory.read_dir(Path::new(&path))
273
+ }
274
+ fn create_dir(&self, path: &Path) -> Result<(), FsError> {
275
+ let path = normalizes_path(path);
276
+ self.memory.create_dir(Path::new(&path))
277
+ }
278
+ fn remove_dir(&self, path: &Path) -> Result<(), FsError> {
279
+ let path = normalizes_path(path);
280
+ let result = self.memory.remove_dir(Path::new(&path));
281
+ if self
282
+ .volumes
283
+ .values()
284
+ .find_map(|v| v.get_file_entry(&path).ok())
285
+ .is_some()
286
+ {
287
+ Ok(())
288
+ } else {
289
+ result
290
+ }
291
+ }
292
+ fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<(), FsError>> {
293
+ Box::pin(async {
294
+ let from = normalizes_path(from);
295
+ let to = normalizes_path(to);
296
+ let result = self.memory.rename(Path::new(&from), Path::new(&to)).await;
297
+ if self
298
+ .volumes
299
+ .values()
300
+ .find_map(|v| v.get_file_entry(&from).ok())
301
+ .is_some()
302
+ {
303
+ Ok(())
304
+ } else {
305
+ result
306
+ }
307
+ })
308
+ }
309
+ fn metadata(&self, path: &Path) -> Result<Metadata, FsError> {
310
+ let path = normalizes_path(path);
311
+ if let Some(fs_entry) = self
312
+ .volumes
313
+ .values()
314
+ .find_map(|v| v.get_file_entry(&path).ok())
315
+ {
316
+ Ok(Metadata {
317
+ ft: translate_file_type(FsEntryType::File),
318
+ accessed: 0,
319
+ created: 0,
320
+ modified: 0,
321
+ len: fs_entry.get_len(),
322
+ })
323
+ } else if let Some(_fs) = self.volumes.values().find_map(|v| v.read_dir(&path).ok()) {
324
+ Ok(Metadata {
325
+ ft: translate_file_type(FsEntryType::Dir),
326
+ accessed: 0,
327
+ created: 0,
328
+ modified: 0,
329
+ len: 0,
330
+ })
331
+ } else {
332
+ self.memory.metadata(Path::new(&path))
333
+ }
334
+ }
335
+ fn remove_file(&self, path: &Path) -> Result<(), FsError> {
336
+ let path = normalizes_path(path);
337
+ let result = self.memory.remove_file(Path::new(&path));
338
+ if self
339
+ .volumes
340
+ .values()
341
+ .find_map(|v| v.get_file_entry(&path).ok())
342
+ .is_some()
343
+ {
344
+ Ok(())
345
+ } else {
346
+ result
347
+ }
348
+ }
349
+ fn new_open_options(&self) -> OpenOptions<'_> {
350
+ OpenOptions::new(self)
351
+ }
352
+ fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> {
353
+ let path = normalizes_path(path);
354
+ if let Some(fs_entry) = self
355
+ .volumes
356
+ .values()
357
+ .find_map(|v| v.get_file_entry(&path).ok())
358
+ {
359
+ Ok(Metadata {
360
+ ft: translate_file_type(FsEntryType::File),
361
+ accessed: 0,
362
+ created: 0,
363
+ modified: 0,
364
+ len: fs_entry.get_len(),
365
+ })
366
+ } else if self
367
+ .volumes
368
+ .values()
369
+ .find_map(|v| v.read_dir(&path).ok())
370
+ .is_some()
371
+ {
372
+ Ok(Metadata {
373
+ ft: translate_file_type(FsEntryType::Dir),
374
+ accessed: 0,
375
+ created: 0,
376
+ modified: 0,
377
+ len: 0,
378
+ })
379
+ } else {
380
+ self.memory.symlink_metadata(Path::new(&path))
381
+ }
382
+ }
383
+ }
384
+
385
+ fn normalizes_path(path: &Path) -> String {
386
+ let path = format!("{}", path.display());
387
+ if !path.starts_with('/') {
388
+ format!("/{path}")
389
+ } else {
390
+ path
391
+ }
392
+ }
393
+
394
+ fn translate_file_type(f: FsEntryType) -> crate::FileType {
395
+ crate::FileType {
396
+ dir: f == FsEntryType::Dir,
397
+ file: f == FsEntryType::File,
398
+ symlink: false,
399
+ char_device: false,
400
+ block_device: false,
401
+ socket: false,
402
+ fifo: false,
403
+ }
404
+ }
405
+
406
+ #[cfg(test)]
407
+ mod tests {
408
+ use super::*;
409
+ use indexmap::IndexMap;
410
+ use std::path::Path;
411
+ use tokio::io::AsyncReadExt;
412
+ use webc::{
413
+ metadata::Manifest,
414
+ v1::{DirOrFile, Volume, WebC},
415
+ };
416
+
417
+ fn fileblock_with_wasm_file() -> &'static [u8] {
418
+ let volume_bytes = Volume::serialize_files(
419
+ [(
420
+ DirOrFile::File(Path::new("lib/python.wasm").to_path_buf()),
421
+ vec![0, 97, 115, 109, 1, 0, 0, 0],
422
+ )]
423
+ .into_iter()
424
+ .collect(),
425
+ );
426
+
427
+ let mut volumes = IndexMap::new();
428
+ volumes.insert("atom".to_string(), Volume::parse(&volume_bytes).unwrap());
429
+
430
+ let fileblock = WebC {
431
+ version: 1,
432
+ checksum: None,
433
+ signature: None,
434
+ manifest: Manifest::default(),
435
+ atoms: Volume::parse(&volume_bytes).unwrap(),
436
+ volumes,
437
+ }
438
+ .get_volumes_as_fileblock();
439
+
440
+ Box::leak(fileblock.into_boxed_slice())
441
+ }
442
+
443
+ #[tokio::test]
444
+ async fn static_webc_reads_advance_the_cursor() {
445
+ let fs = StaticFileSystem::init(fileblock_with_wasm_file(), "python").unwrap();
446
+ let mut file = fs
447
+ .new_open_options()
448
+ .read(true)
449
+ .open("/lib/python.wasm")
450
+ .unwrap();
451
+
452
+ let mut first = [0; 4];
453
+ file.read_exact(&mut first).await.unwrap();
454
+ assert_eq!(&first, b"\0asm");
455
+
456
+ let mut second = [0; 4];
457
+ file.read_exact(&mut second).await.unwrap();
458
+ assert_eq!(second, [1, 0, 0, 0]);
459
+ }
460
+ }
@@ -0,0 +1,95 @@
1
+ //! Wraps the memory file system implementation - this has been
2
+ //! enhanced to support shared static files, readonly files, etc...
3
+
4
+ use std::path::{Path, PathBuf};
5
+
6
+ use crate::{
7
+ BoxFuture, FileSystem, Metadata, OpenOptions, ReadDir, Result, limiter::DynFsMemoryLimiter,
8
+ mem_fs,
9
+ };
10
+
11
+ #[derive(Debug, Default, Clone)]
12
+ pub struct TmpFileSystem {
13
+ fs: mem_fs::FileSystem,
14
+ }
15
+
16
+ impl TmpFileSystem {
17
+ pub fn new() -> Self {
18
+ Self::default()
19
+ }
20
+
21
+ /// Creates a temporary filesystem with a fixed timestamp for every
22
+ /// implicit metadata update.
23
+ pub fn with_fixed_timestamp(timestamp: u64) -> Self {
24
+ Self {
25
+ fs: mem_fs::FileSystem::with_fixed_timestamp(timestamp),
26
+ }
27
+ }
28
+
29
+ pub fn set_memory_limiter(&self, limiter: DynFsMemoryLimiter) {
30
+ self.fs.set_memory_limiter(limiter);
31
+ }
32
+
33
+ pub fn new_open_options_ext(&self) -> &mem_fs::FileSystem {
34
+ self.fs.new_open_options_ext()
35
+ }
36
+
37
+ pub fn union(&self, other: &std::sync::Arc<dyn FileSystem + Send + Sync>) {
38
+ self.fs.union(other)
39
+ }
40
+
41
+ /// Canonicalize a path without validating that it actually exists.
42
+ pub fn canonicalize_unchecked(&self, path: &Path) -> Result<PathBuf> {
43
+ self.fs.canonicalize_unchecked(path)
44
+ }
45
+
46
+ pub fn create_symlink(&self, source: &Path, target: &Path) -> Result<()> {
47
+ self.fs.create_symlink(source, target)
48
+ }
49
+ }
50
+
51
+ impl FileSystem for TmpFileSystem {
52
+ fn readlink(&self, path: &Path) -> Result<PathBuf> {
53
+ self.fs.readlink(path)
54
+ }
55
+
56
+ fn read_dir(&self, path: &Path) -> Result<ReadDir> {
57
+ self.fs.read_dir(path)
58
+ }
59
+
60
+ fn create_dir(&self, path: &Path) -> Result<()> {
61
+ self.fs.create_dir(path)
62
+ }
63
+
64
+ fn create_symlink(&self, source: &Path, target: &Path) -> Result<()> {
65
+ self.fs.create_symlink(source, target)
66
+ }
67
+
68
+ fn hard_link(&self, source: &Path, target: &Path) -> Result<()> {
69
+ self.fs.hard_link(source, target)
70
+ }
71
+
72
+ fn remove_dir(&self, path: &Path) -> Result<()> {
73
+ self.fs.remove_dir(path)
74
+ }
75
+
76
+ fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> {
77
+ Box::pin(async { self.fs.rename(from, to).await })
78
+ }
79
+
80
+ fn metadata(&self, path: &Path) -> Result<Metadata> {
81
+ self.fs.metadata(path)
82
+ }
83
+
84
+ fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
85
+ self.fs.symlink_metadata(path)
86
+ }
87
+
88
+ fn remove_file(&self, path: &Path) -> Result<()> {
89
+ self.fs.remove_file(path)
90
+ }
91
+
92
+ fn new_open_options(&self) -> OpenOptions<'_> {
93
+ self.fs.new_open_options()
94
+ }
95
+ }