vortex_io/filesystem/
prefix.rs1use std::sync::Arc;
5
6use async_trait::async_trait;
7use futures::StreamExt;
8use futures::stream::BoxStream;
9use vortex_error::VortexResult;
10
11use crate::VortexReadAt;
12use crate::filesystem::FileListing;
13use crate::filesystem::FileSystem;
14use crate::filesystem::FileSystemRef;
15
16#[derive(Debug)]
21pub struct PrefixFileSystem {
22 inner: FileSystemRef,
23 prefix: String,
24}
25
26impl PrefixFileSystem {
27 pub fn new(inner: FileSystemRef, prefix: String) -> Self {
28 let prefix = format!("{}/", prefix.trim_matches('/'));
30 Self { inner, prefix }
31 }
32}
33
34#[async_trait]
35impl FileSystem for PrefixFileSystem {
36 fn list(&self, prefix: &str) -> BoxStream<'_, VortexResult<FileListing>> {
37 let full_prefix = format!("{}{}", self.prefix, prefix.trim_start_matches('/'));
38
39 let strip_prefix = self.prefix.clone();
40 self.inner
41 .list(&full_prefix)
42 .map(move |result| {
43 result.map(|mut listing| {
44 listing.path = listing
45 .path
46 .strip_prefix(&strip_prefix)
47 .unwrap_or(&listing.path)
48 .to_string();
49 listing
50 })
51 })
52 .boxed()
53 }
54
55 async fn open_read(&self, path: &str) -> VortexResult<Arc<dyn VortexReadAt>> {
56 self.inner
57 .open_read(&format!("{}{}", self.prefix, path.trim_start_matches('/')))
58 .await
59 }
60}
61
62impl dyn FileSystem + 'static {
63 pub fn with_prefix(self: Arc<Self>, prefix: String) -> FileSystemRef {
65 Arc::new(PrefixFileSystem::new(self, prefix))
66 }
67}