1use std::path::Path;
2
3use dada_util::Fallible;
4use url::Url;
5
6pub trait VirtualFileSystem: Send + Sync + 'static {
7 fn contents(&self, url: &Url) -> Fallible<String>;
9
10 fn exists(&self, url: &Url) -> bool;
12
13 fn path_url(&self, path: &Path) -> Fallible<Url>;
15
16 fn url_display(&self, url: &Url) -> String;
18}
19
20#[derive(Clone, Debug)]
21pub(crate) struct UrlPath {
22 source_url: Url,
23 paths: Vec<String>,
24}
25
26impl From<Url> for UrlPath {
27 fn from(url: Url) -> Self {
28 let paths = url
29 .path()
30 .split("/")
31 .filter(|s| !s.is_empty())
32 .map(|s| s.to_string())
33 .collect();
34
35 Self {
36 source_url: url,
37 paths,
38 }
39 }
40}
41
42impl UrlPath {
43 pub fn is_empty(&self) -> bool {
44 self.paths.is_empty()
45 }
46
47 pub fn pop(mut self) -> Self {
50 self.paths.pop();
51 self
52 }
53
54 pub fn push(&mut self, s: &str) {
56 assert!(!self.is_dada_file());
57 self.paths.push(s.to_string());
58 }
59
60 pub fn is_dada_file(&self) -> bool {
62 let Some(last) = self.paths.last() else {
63 return false;
64 };
65
66 last.ends_with(".dada")
67 }
68
69 pub fn final_module_name(&self) -> &str {
71 assert!(self.is_dada_file());
72
73 let Some(last) = self.paths.last() else {
74 unreachable!()
75 };
76
77 &last[0..last.len() - ".dada".len()]
78 }
79 pub fn make_directory(mut self) -> Self {
85 assert!(self.is_dada_file());
86
87 let Some(last) = self.paths.last_mut() else {
88 unreachable!()
89 };
90
91 assert!(last.ends_with(".dada"));
92 last.truncate(last.len() - ".dada".len());
93 self
94 }
95
96 pub fn make_dada_file(mut self) -> Self {
102 assert!(!self.is_dada_file());
103
104 let Some(last) = self.paths.last_mut() else {
105 self.paths.push(".dada".to_string());
106 return self;
107 };
108
109 last.push_str(".dada");
110 self
111 }
112
113 pub fn dada_url(&self) -> Url {
119 assert!(!self.is_dada_file());
120 let mut path = self.paths.join("/");
121 path.push_str(".dada");
122
123 let mut url = self.source_url.clone();
124 url.set_path(&path);
125
126 url
127 }
128
129 pub fn url(&self) -> Url {
131 let path = self.paths.join("/");
132 let mut url = self.source_url.clone();
133 url.set_path(&path);
134 url
135 }
136}
137
138pub trait ToUrl {
139 fn to_url(&self, vfs: &dyn VirtualFileSystem) -> Fallible<Url>;
140}
141
142impl ToUrl for str {
143 fn to_url(&self, _vfs: &dyn VirtualFileSystem) -> Fallible<Url> {
144 Ok(Url::parse(self)?)
145 }
146}
147
148impl ToUrl for Url {
149 fn to_url(&self, _vfs: &dyn VirtualFileSystem) -> Fallible<Url> {
150 Ok(self.clone())
151 }
152}
153
154impl ToUrl for Path {
155 fn to_url(&self, vfs: &dyn VirtualFileSystem) -> Fallible<Url> {
156 vfs.path_url(self)
157 }
158}