1use crate::{FileMetadata, FileType, Vfs, WritableVfs};
2use oak_core::{
3 Arc,
4 source::{SourceId, SourceText},
5};
6use std::{
7 collections::HashMap,
8 sync::{
9 RwLock,
10 atomic::{AtomicU32, Ordering},
11 },
12};
13
14#[derive(Default)]
17pub struct MemoryVfs {
18 files: std::sync::Arc<RwLock<HashMap<Arc<str>, FileEntry>>>,
19 ids: std::sync::Arc<RwLock<HashMap<SourceId, Arc<str>>>>,
20 uri_to_id: std::sync::Arc<RwLock<HashMap<Arc<str>, SourceId>>>,
21 next_id: std::sync::Arc<AtomicU32>,
22}
23
24impl Clone for MemoryVfs {
25 fn clone(&self) -> Self {
26 Self { files: self.files.clone(), ids: self.ids.clone(), uri_to_id: self.uri_to_id.clone(), next_id: self.next_id.clone() }
27 }
28}
29
30struct FileEntry {
31 content: Arc<str>,
32 modified: u64,
33 id: SourceId,
34}
35
36impl MemoryVfs {
37 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn write_file(&self, uri: &str, content: impl Into<Arc<str>>) {
44 let uri_arc: Arc<str> = Arc::from(uri);
45 let mut files = self.files.write().unwrap();
46 let mut ids = self.ids.write().unwrap();
47 let mut uri_to_id = self.uri_to_id.write().unwrap();
48
49 let id = if let Some(id) = uri_to_id.get(&uri_arc) {
50 *id
51 }
52 else {
53 let id = self.next_id.fetch_add(1, Ordering::SeqCst);
54 uri_to_id.insert(uri_arc.clone(), id);
55 ids.insert(id, uri_arc.clone());
56 id
57 };
58
59 files.insert(uri_arc, FileEntry { content: content.into(), modified: Self::now(), id });
60 }
61
62 pub fn remove_file(&self, uri: &str) {
64 let mut files = self.files.write().unwrap();
65 let mut ids = self.ids.write().unwrap();
66 let mut uri_to_id = self.uri_to_id.write().unwrap();
67
68 if let Some(entry) = files.remove(uri) {
69 uri_to_id.remove(uri);
70 ids.remove(&entry.id);
71 }
72 }
73
74 fn now() -> u64 {
75 #[cfg(not(target_arch = "wasm32"))]
78 {
79 std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_secs()
80 }
81 #[cfg(target_arch = "wasm32")]
82 {
83 0 }
85 }
86}
87
88impl Vfs for MemoryVfs {
89 type Source = SourceText;
90
91 fn get_source(&self, uri: &str) -> Option<SourceText> {
92 let files = self.files.read().unwrap();
93 files.get(uri).map(|entry| SourceText::new_with_id(entry.content.clone(), entry.id))
94 }
95
96 fn get_uri(&self, id: SourceId) -> Option<Arc<str>> {
97 let ids = self.ids.read().unwrap();
98 ids.get(&id).cloned()
99 }
100
101 fn get_id(&self, uri: &str) -> Option<SourceId> {
102 let uri_to_id = self.uri_to_id.read().unwrap();
103 uri_to_id.get(uri).cloned()
104 }
105
106 fn exists(&self, uri: &str) -> bool {
107 self.files.read().unwrap().contains_key(uri)
108 }
109
110 fn metadata(&self, uri: &str) -> Option<FileMetadata> {
111 let files = self.files.read().unwrap();
112 files.get(uri).map(|entry| FileMetadata { file_type: FileType::File, len: entry.content.len() as u64, modified: Some(entry.modified) })
113 }
114
115 fn read_dir(&self, _uri: &str) -> Option<Vec<Arc<str>>> {
116 let files = self.files.read().unwrap();
119 Some(files.keys().cloned().collect())
120 }
121}
122
123impl WritableVfs for MemoryVfs {
124 fn write_file(&self, uri: &str, content: Arc<str>) {
125 self.write_file(uri, content);
126 }
127
128 fn remove_file(&self, uri: &str) {
129 self.remove_file(uri);
130 }
131}