1use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::Vec};
2use core::{error::Error, fmt::Debug};
3
4use super::*;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
13#[cfg_attr(feature = "serde", serde(transparent))]
14pub struct SourceId(u32);
15
16impl Default for SourceId {
17 fn default() -> Self {
18 Self::UNKNOWN
19 }
20}
21
22impl SourceId {
23 pub const UNKNOWN: Self = Self(u32::MAX);
24
25 pub fn new(id: u32) -> Self {
27 assert_ne!(id, u32::MAX, "u32::MAX is a reserved value for SourceId::default()/UNKNOWN");
28
29 Self(id)
30 }
31
32 #[inline(always)]
34 pub const fn new_unchecked(id: u32) -> Self {
35 Self(id)
36 }
37
38 #[inline(always)]
39 pub const fn to_usize(self) -> usize {
40 self.0 as usize
41 }
42
43 #[inline(always)]
44 pub const fn to_u32(self) -> u32 {
45 self.0
46 }
47
48 pub const fn is_unknown(&self) -> bool {
49 self.0 == u32::MAX
50 }
51}
52
53impl TryFrom<usize> for SourceId {
54 type Error = ();
55
56 #[inline]
57 fn try_from(id: usize) -> Result<Self, Self::Error> {
58 match u32::try_from(id) {
59 Ok(n) if n < u32::MAX => Ok(Self(n)),
60 _ => Err(()),
61 }
62 }
63}
64
65#[derive(Debug, thiserror::Error)]
70pub enum SourceManagerError {
71 #[error("attempted to use an invalid source id")]
74 InvalidSourceId,
75 #[error("attempted to read content out of bounds")]
77 InvalidBounds,
78 #[error(transparent)]
79 InvalidContentUpdate(#[from] SourceContentUpdateError),
80 #[error("{error_msg}")]
82 Custom {
83 error_msg: Box<str>,
84 source: Option<Box<dyn Error + Send + Sync + 'static>>,
86 },
87}
88
89impl SourceManagerError {
90 pub fn custom(message: String) -> Self {
91 Self::Custom { error_msg: message.into(), source: None }
92 }
93
94 pub fn custom_with_source(message: String, source: impl Error + Send + Sync + 'static) -> Self {
95 Self::Custom {
96 error_msg: message.into(),
97 source: Some(Box::new(source)),
98 }
99 }
100}
101
102pub trait SourceManager: Debug {
103 fn is_manager_of(&self, file: &SourceFile) -> bool {
105 match self.get(file.id()) {
106 Ok(found) => core::ptr::addr_eq(Arc::as_ptr(&found), file),
107 Err(_) => false,
108 }
109 }
110 fn copy_into(&self, file: &SourceFile) -> Arc<SourceFile> {
114 if let Ok(found) = self.get(file.id())
115 && core::ptr::addr_eq(Arc::as_ptr(&found), file)
116 {
117 return found;
118 }
119 self.load_from_raw_parts(file.uri().clone(), file.content().clone())
120 }
121 fn load(&self, lang: SourceLanguage, name: Uri, content: String) -> Arc<SourceFile> {
123 let content = SourceContent::new(lang, name.clone(), content);
124 self.load_from_raw_parts(name, content)
125 }
126 fn load_from_raw_parts(&self, name: Uri, content: SourceContent) -> Arc<SourceFile>;
128 fn update(
132 &self,
133 id: SourceId,
134 text: String,
135 range: Option<Selection>,
136 version: i32,
137 ) -> Result<(), SourceManagerError>;
138 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError>;
140 fn get_by_uri(&self, uri: &Uri) -> Option<Arc<SourceFile>> {
142 self.find(uri).and_then(|id| self.get(id).ok())
143 }
144 fn find(&self, uri: &Uri) -> Option<SourceId>;
146 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan>;
148 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError>;
150 fn location_to_span(&self, loc: Location) -> Option<SourceSpan>;
152 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError>;
154 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError>;
156 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError>;
158}
159
160impl<T: ?Sized + SourceManager> SourceManager for Arc<T> {
161 #[inline(always)]
162 fn is_manager_of(&self, file: &SourceFile) -> bool {
163 (**self).is_manager_of(file)
164 }
165 #[inline(always)]
166 fn copy_into(&self, file: &SourceFile) -> Arc<SourceFile> {
167 (**self).copy_into(file)
168 }
169 #[inline(always)]
170 fn load(&self, lang: SourceLanguage, uri: Uri, content: String) -> Arc<SourceFile> {
171 (**self).load(lang, uri, content)
172 }
173 #[inline(always)]
174 fn load_from_raw_parts(&self, uri: Uri, content: SourceContent) -> Arc<SourceFile> {
175 (**self).load_from_raw_parts(uri, content)
176 }
177 #[inline(always)]
178 fn update(
179 &self,
180 id: SourceId,
181 text: String,
182 range: Option<Selection>,
183 version: i32,
184 ) -> Result<(), SourceManagerError> {
185 (**self).update(id, text, range, version)
186 }
187 #[inline(always)]
188 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
189 (**self).get(id)
190 }
191 #[inline(always)]
192 fn get_by_uri(&self, uri: &Uri) -> Option<Arc<SourceFile>> {
193 (**self).get_by_uri(uri)
194 }
195 #[inline(always)]
196 fn find(&self, uri: &Uri) -> Option<SourceId> {
197 (**self).find(uri)
198 }
199 #[inline(always)]
200 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
201 (**self).file_line_col_to_span(loc)
202 }
203 #[inline(always)]
204 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
205 (**self).file_line_col(span)
206 }
207 #[inline(always)]
208 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
209 (**self).location_to_span(loc)
210 }
211 #[inline(always)]
212 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
213 (**self).location(span)
214 }
215 #[inline(always)]
216 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError> {
217 (**self).source(id)
218 }
219 #[inline(always)]
220 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError> {
221 (**self).source_slice(span)
222 }
223}
224
225#[cfg(feature = "std")]
226pub trait SourceManagerExt: SourceManager {
227 fn load_file(&self, path: &std::path::Path) -> Result<Arc<SourceFile>, SourceManagerError> {
229 let uri = Uri::from(path);
230 if let Some(existing) = self.get_by_uri(&uri) {
231 return Ok(existing);
232 }
233
234 let lang = match path.extension().and_then(|ext| ext.to_str()) {
235 Some("masm") => "masm",
236 Some("rs") => "rust",
237 Some(ext) => ext,
238 None => "unknown",
239 };
240
241 let content = std::fs::read_to_string(path)
242 .map(|s| SourceContent::new(lang, uri.clone(), s))
243 .map_err(|source| {
244 SourceManagerError::custom_with_source(
245 alloc::format!("failed to load filed at `{}`", path.display()),
246 source,
247 )
248 })?;
249
250 Ok(self.load_from_raw_parts(uri, content))
251 }
252}
253
254#[cfg(feature = "std")]
255impl<T: ?Sized + SourceManager> SourceManagerExt for T {}
256
257pub trait SourceManagerSync: SourceManager + Send + Sync {}
264
265impl<T: ?Sized + SourceManager + Send + Sync> SourceManagerSync for T {}
266
267use miden_utils_sync::RwLock;
271
272#[derive(Debug, Default)]
273pub struct DefaultSourceManager(RwLock<DefaultSourceManagerImpl>);
274impl Clone for DefaultSourceManager {
275 fn clone(&self) -> Self {
276 let manager = self.0.read();
277 Self(RwLock::new(manager.clone()))
278 }
279}
280
281#[derive(Debug, Default, Clone)]
282struct DefaultSourceManagerImpl {
283 files: Vec<Arc<SourceFile>>,
284 uris: BTreeMap<Uri, SourceId>,
285}
286
287impl DefaultSourceManagerImpl {
288 fn insert(&mut self, uri: Uri, content: SourceContent) -> Arc<SourceFile> {
289 if let Some(file) = self.uris.get(&uri).copied().and_then(|id| {
292 let file = &self.files[id.to_usize()];
293 if file.as_str() == content.as_str() {
294 Some(Arc::clone(file))
295 } else {
296 None
297 }
298 }) {
299 return file;
300 }
301 let id = SourceId::try_from(self.files.len())
302 .expect("system limit: source manager has exhausted its supply of source ids");
303 let file = Arc::new(SourceFile::from_raw_parts(id, content));
304 self.files.push(Arc::clone(&file));
305 self.uris.insert(uri.clone(), id);
306 file
307 }
308
309 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
310 self.files
311 .get(id.to_usize())
312 .cloned()
313 .ok_or(SourceManagerError::InvalidSourceId)
314 }
315
316 fn get_by_uri(&self, uri: &Uri) -> Option<Arc<SourceFile>> {
317 self.find(uri).and_then(|id| self.get(id).ok())
318 }
319
320 fn find(&self, uri: &Uri) -> Option<SourceId> {
321 self.uris.get(uri).copied()
322 }
323
324 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
325 let file = self.uris.get(&loc.uri).copied().and_then(|id| self.files.get(id.to_usize()))?;
326 file.line_column_to_span(loc.line, loc.column)
327 }
328
329 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
330 self.files
331 .get(span.source_id().to_usize())
332 .ok_or(SourceManagerError::InvalidSourceId)
333 .map(|file| file.location(span))
334 }
335
336 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
337 let file = self.uris.get(&loc.uri).copied().and_then(|id| self.files.get(id.to_usize()))?;
338
339 let max_len = ByteIndex::from(file.as_str().len() as u32);
340 if loc.start >= max_len || loc.end > max_len {
341 return None;
342 }
343
344 Some(SourceSpan::new(file.id(), loc.start..loc.end))
345 }
346
347 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
348 self.files
349 .get(span.source_id().to_usize())
350 .ok_or(SourceManagerError::InvalidSourceId)
351 .map(|file| Location::new(file.uri().clone(), span.start(), span.end()))
352 }
353}
354
355impl SourceManager for DefaultSourceManager {
356 fn load_from_raw_parts(&self, uri: Uri, content: SourceContent) -> Arc<SourceFile> {
357 let mut manager = self.0.write();
358 manager.insert(uri, content)
359 }
360
361 fn update(
362 &self,
363 id: SourceId,
364 text: String,
365 range: Option<Selection>,
366 version: i32,
367 ) -> Result<(), SourceManagerError> {
368 let mut manager = self.0.write();
369 let source_file = manager
370 .files
371 .get_mut(id.to_usize())
372 .ok_or(SourceManagerError::InvalidSourceId)?;
373 let source_file = Arc::make_mut(source_file);
374 source_file
375 .content_mut()
376 .update(text, range, version)
377 .map_err(SourceManagerError::InvalidContentUpdate)
378 }
379
380 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
381 let manager = self.0.read();
382 manager.get(id)
383 }
384
385 fn get_by_uri(&self, uri: &Uri) -> Option<Arc<SourceFile>> {
386 let manager = self.0.read();
387 manager.get_by_uri(uri)
388 }
389
390 fn find(&self, uri: &Uri) -> Option<SourceId> {
391 let manager = self.0.read();
392 manager.find(uri)
393 }
394
395 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
396 let manager = self.0.read();
397 manager.file_line_col_to_span(loc)
398 }
399
400 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
401 let manager = self.0.read();
402 manager.file_line_col(span)
403 }
404
405 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
406 let manager = self.0.read();
407 manager.location_to_span(loc)
408 }
409
410 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
411 let manager = self.0.read();
412 manager.location(span)
413 }
414
415 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError> {
416 let manager = self.0.read();
417 let ptr = manager
418 .files
419 .get(id.to_usize())
420 .ok_or(SourceManagerError::InvalidSourceId)
421 .map(|file| file.as_str() as *const str)?;
422 drop(manager);
423 Ok(unsafe { &*ptr })
428 }
429
430 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError> {
431 self.source(span.source_id())?
432 .get(span.into_slice_index())
433 .ok_or(SourceManagerError::InvalidBounds)
434 }
435}
436
437#[cfg(test)]
438mod error_assertions {
439 use super::*;
440
441 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
443
444 fn _assert_source_manager_error_bounds(err: SourceManagerError) {
445 _assert_error_is_send_sync_static(err);
446 }
447}