1use core::{error::Error, fmt::Debug};
2use std::{collections::BTreeMap, sync::Arc};
3
4use serde::{Deserialize, Serialize};
5
6use super::*;
7use crate::range::Range;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10#[repr(u32)]
11pub enum SourceGroup {
12 File = 0,
13 Argument = ((u8::MAX - 1) as u32) << 24,
14 Unknown = (u8::MAX as u32) << 24,
15}
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20pub struct SourceId(u32);
21
22impl From<u32> for SourceId {
23 fn from(value: u32) -> Self {
24 SourceId::new_unchecked(value)
25 }
26}
27
28impl Default for SourceId {
29 fn default() -> Self {
30 Self::UNKNOWN
31 }
32}
33
34impl SourceId {
35 pub const UNKNOWN: Self = Self(u32::MAX);
36
37 const GROUP_MASK: u32 = (u8::MAX as u32) << 24;
38 const INDEX_MASK: u32 = !Self::GROUP_MASK;
39 const MAX_INDEX: u32 = Self::INDEX_MASK;
40
41 pub fn file(id: u32) -> Self {
43 assert!(
44 id <= Self::MAX_INDEX,
45 "source id out of range: only 2^24 unique ids can be represented"
46 );
47
48 Self(id | SourceGroup::File as u32)
49 }
50
51 pub fn argument(id: u32) -> Self {
54 assert!(
55 id <= Self::MAX_INDEX,
56 "source id out of range: only 2^24 unique ids can be represented"
57 );
58
59 Self(id | SourceGroup::Argument as u32)
60 }
61
62 #[inline(always)]
64 pub const fn new_unchecked(id: u32) -> Self {
65 assert!(
66 id & Self::GROUP_MASK == (SourceGroup::File as u32),
67 "invalid source id group: expected file"
68 );
69 Self(id)
70 }
71
72 #[inline(always)]
73 pub const fn to_index(self) -> usize {
74 (self.0 & Self::INDEX_MASK) as usize
75 }
76
77 #[inline(always)]
78 pub const fn group(&self) -> SourceGroup {
79 let group = self.0 & Self::GROUP_MASK;
80 unsafe { *(&group as *const u32).cast::<SourceGroup>() }
82 }
83
84 #[inline(always)]
85 pub const fn to_u32(self) -> u32 {
86 self.0
87 }
88
89 pub const fn is_unknown(&self) -> bool {
90 self.0 == Self::UNKNOWN.0
91 }
92
93 pub const fn is_cli_argument(&self) -> bool {
94 matches!(self.group(), SourceGroup::Argument)
95 }
96}
97
98impl TryFrom<usize> for SourceId {
99 type Error = ();
100
101 #[inline]
102 fn try_from(id: usize) -> Result<Self, Self::Error> {
103 match u32::try_from(id) {
104 Ok(n) if n & SourceId::GROUP_MASK == 0 => Ok(Self(n)),
105 _ => Err(()),
106 }
107 }
108}
109
110#[derive(Debug, thiserror::Error)]
115pub enum SourceManagerError {
116 #[error("attempted to use an invalid source id")]
119 InvalidSourceId,
120 #[error("attempted to read content out of bounds")]
122 InvalidBounds,
123 #[error(transparent)]
124 InvalidContentUpdate(#[from] SourceContentUpdateError),
125 #[error("{error_msg}")]
127 Custom {
128 error_msg: Box<str>,
129 source: Option<Box<dyn Error + Send + Sync + 'static>>,
131 },
132}
133
134impl SourceManagerError {
135 pub fn custom(message: String) -> Self {
136 Self::Custom {
137 error_msg: message.into(),
138 source: None,
139 }
140 }
141
142 pub fn custom_with_source(message: String, source: impl Error + Send + Sync + 'static) -> Self {
143 Self::Custom {
144 error_msg: message.into(),
145 source: Some(Box::new(source)),
146 }
147 }
148}
149
150pub trait SourceManager: Debug {
151 fn is_manager_of(&self, file: &SourceFile) -> bool {
153 match self.get(file.id()) {
154 Ok(found) => core::ptr::addr_eq(Arc::as_ptr(&found), file),
155 Err(_) => false,
156 }
157 }
158 fn copy_into(&self, file: &SourceFile) -> Arc<SourceFile> {
162 if let Ok(found) = self.get(file.id())
163 && core::ptr::addr_eq(Arc::as_ptr(&found), file)
164 {
165 return found;
166 }
167 self.load_from_raw_parts(
168 file.id().group(),
169 file.uri().clone(),
170 file.content().clone(),
171 )
172 }
173 fn load_argument(&self, name: &'static str, content: String) -> Arc<SourceFile> {
174 let content = SourceContent::new(SourceLanguage::Unknown, name, content);
175 self.load_from_raw_parts(
176 SourceGroup::Argument,
177 FileName::from_static_str(name),
178 content,
179 )
180 }
181 fn load(&self, lang: SourceLanguage, name: FileName, content: String) -> Arc<SourceFile> {
183 let content = SourceContent::new(lang, name.clone(), content);
184 self.load_from_raw_parts(SourceGroup::File, name, content)
185 }
186 fn load_from_raw_parts(
188 &self,
189 group: SourceGroup,
190 name: FileName,
191 content: SourceContent,
192 ) -> Arc<SourceFile>;
193 fn update(
197 &self,
198 id: SourceId,
199 text: String,
200 range: Option<Selection>,
201 version: i32,
202 ) -> Result<(), SourceManagerError>;
203 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError>;
205 fn get_by_uri(&self, uri: &FileName) -> Option<Arc<SourceFile>> {
207 self.find(uri).and_then(|id| self.get(id).ok())
208 }
209 fn find(&self, uri: &FileName) -> Option<SourceId>;
211 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan>;
213 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError>;
215 fn location_to_span(&self, loc: Location) -> Option<SourceSpan>;
217 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError>;
219 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError>;
221 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError>;
223}
224
225impl<T: ?Sized + SourceManager> SourceManager for Arc<T> {
226 #[inline(always)]
227 fn is_manager_of(&self, file: &SourceFile) -> bool {
228 (**self).is_manager_of(file)
229 }
230 #[inline(always)]
231 fn copy_into(&self, file: &SourceFile) -> Arc<SourceFile> {
232 (**self).copy_into(file)
233 }
234 #[inline(always)]
235 fn load(&self, lang: SourceLanguage, uri: FileName, content: String) -> Arc<SourceFile> {
236 (**self).load(lang, uri, content)
237 }
238 #[inline(always)]
239 fn load_from_raw_parts(
240 &self,
241 group: SourceGroup,
242 uri: FileName,
243 content: SourceContent,
244 ) -> Arc<SourceFile> {
245 (**self).load_from_raw_parts(group, uri, content)
246 }
247 #[inline(always)]
248 fn update(
249 &self,
250 id: SourceId,
251 text: String,
252 range: Option<Selection>,
253 version: i32,
254 ) -> Result<(), SourceManagerError> {
255 (**self).update(id, text, range, version)
256 }
257 #[inline(always)]
258 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
259 (**self).get(id)
260 }
261 #[inline(always)]
262 fn get_by_uri(&self, uri: &FileName) -> Option<Arc<SourceFile>> {
263 (**self).get_by_uri(uri)
264 }
265 #[inline(always)]
266 fn find(&self, uri: &FileName) -> Option<SourceId> {
267 (**self).find(uri)
268 }
269 #[inline(always)]
270 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
271 (**self).file_line_col_to_span(loc)
272 }
273 #[inline(always)]
274 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
275 (**self).file_line_col(span)
276 }
277 #[inline(always)]
278 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
279 (**self).location_to_span(loc)
280 }
281 #[inline(always)]
282 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
283 (**self).location(span)
284 }
285 #[inline(always)]
286 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError> {
287 (**self).source(id)
288 }
289 #[inline(always)]
290 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError> {
291 (**self).source_slice(span)
292 }
293}
294
295pub trait SourceManagerExt: SourceManager {
296 fn load_file(&self, path: &std::path::Path) -> Result<Arc<SourceFile>, SourceManagerError> {
298 let uri = FileName::from(path);
299 if let Some(existing) = self.get_by_uri(&uri) {
300 return Ok(existing);
301 }
302
303 let lang = SourceLanguage::from_path(path);
304 let content = std::fs::read_to_string(path)
305 .map(|s| SourceContent::new(lang, uri.clone(), s))
306 .map_err(|source| {
307 SourceManagerError::custom_with_source(
308 format!("failed to load filed at `{}`", path.display()),
309 source,
310 )
311 })?;
312
313 Ok(self.load_from_raw_parts(SourceGroup::File, uri, content))
314 }
315}
316
317impl<T: ?Sized + SourceManager> SourceManagerExt for T {}
318
319pub trait SourceManagerSync: SourceManager + Send + Sync {}
326
327impl<T: ?Sized + SourceManager + Send + Sync> SourceManagerSync for T {}
328
329use parking_lot::RwLock;
333
334#[derive(Debug, Default)]
335pub struct DefaultSourceManager(RwLock<DefaultSourceManagerImpl>);
336
337impl Clone for DefaultSourceManager {
338 fn clone(&self) -> Self {
339 let manager = self.0.read();
340 Self(RwLock::new(manager.clone()))
341 }
342}
343
344impl Clone for DefaultSourceManagerImpl {
345 fn clone(&self) -> Self {
346 Self {
347 files: self.files.clone(),
348 arguments: self.arguments.clone(),
349 uris: self.uris.clone(),
350 }
351 }
352}
353
354#[derive(Debug, Default)]
355struct DefaultSourceManagerImpl {
356 files: Vec<Arc<SourceFile>>,
357 arguments: Vec<Arc<SourceFile>>,
358 uris: BTreeMap<FileName, SourceId>,
359}
360
361impl DefaultSourceManagerImpl {
362 fn insert(
363 &mut self,
364 group: SourceGroup,
365 uri: FileName,
366 content: SourceContent,
367 ) -> Arc<SourceFile> {
368 if let Some(file) = self.uris.get(&uri).copied().and_then(|id| {
371 let file = if id.is_cli_argument() {
372 &self.arguments[id.to_index()]
373 } else {
374 &self.files[id.to_index()]
375 };
376 if file.as_str() == content.as_str() {
377 Some(Arc::clone(file))
378 } else {
379 None
380 }
381 }) {
382 return file;
383 }
384 match group {
385 SourceGroup::File => {
386 let index = u32::try_from(self.files.len())
387 .expect("system limit: too many source files tracked");
388 let id = SourceId::file(index);
389 let file = Arc::new(SourceFile::from_raw_parts(id, content));
390 self.files.push(Arc::clone(&file));
391 self.uris.insert(uri, id);
392 file
393 }
394 SourceGroup::Argument => {
395 let index = u32::try_from(self.arguments.len())
396 .expect("system limit: too many argument sources tracked");
397 let id = SourceId::argument(index);
398 let file = Arc::new(SourceFile::from_raw_parts(id, content));
399 self.arguments.push(Arc::clone(&file));
400 self.uris.insert(uri, id);
401 file
402 }
403 SourceGroup::Unknown => unreachable!(),
404 }
405 }
406
407 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
408 if id.is_cli_argument() {
409 self.arguments
410 .get(id.to_index())
411 .cloned()
412 .ok_or(SourceManagerError::InvalidSourceId)
413 } else {
414 self.files
415 .get(id.to_index())
416 .cloned()
417 .ok_or(SourceManagerError::InvalidSourceId)
418 }
419 }
420
421 fn get_by_uri(&self, uri: &FileName) -> Option<Arc<SourceFile>> {
422 self.find(uri).and_then(|id| self.get(id).ok())
423 }
424
425 fn find(&self, uri: &FileName) -> Option<SourceId> {
426 self.uris.get(uri).copied()
427 }
428
429 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
430 let file = self
431 .uris
432 .get(&loc.uri)
433 .copied()
434 .and_then(|id| self.get(id).ok())?;
435 file.line_column_to_span(loc.line, loc.column)
436 }
437
438 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
439 self.get(span.source_id()).map(|file| file.location(span))
440 }
441
442 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
443 let file = self
444 .uris
445 .get(&loc.uri)
446 .copied()
447 .and_then(|id| self.get(id).ok())?;
448
449 let max_len = ByteIndex::from(file.as_str().len() as u32);
450 if loc.start >= max_len || loc.end > max_len {
451 return None;
452 }
453
454 Some(SourceSpan::new(file.id(), Range::new(loc.start, loc.end)))
455 }
456
457 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
458 self.get(span.source_id())
459 .map(|file| Location::new(file.uri().clone(), span.start(), span.end()))
460 }
461}
462
463impl SourceManager for DefaultSourceManager {
464 fn load_from_raw_parts(
465 &self,
466 group: SourceGroup,
467 uri: FileName,
468 content: SourceContent,
469 ) -> Arc<SourceFile> {
470 let mut manager = self.0.write();
471 manager.insert(group, uri, content)
472 }
473
474 fn update(
475 &self,
476 id: SourceId,
477 text: String,
478 range: Option<Selection>,
479 version: i32,
480 ) -> Result<(), SourceManagerError> {
481 let mut manager = self.0.write();
482 match id.group() {
483 SourceGroup::File => {
484 let source_file = &mut manager.files[id.to_index()];
485 let source_file_cloned = Arc::make_mut(source_file);
486 source_file_cloned
487 .content_mut()
488 .update(text, range, version)
489 .map_err(SourceManagerError::InvalidContentUpdate)
490 }
491 SourceGroup::Argument => {
492 let source_file = &mut manager.arguments[id.to_index()];
493 let source_file_cloned = Arc::make_mut(source_file);
494 source_file_cloned
495 .content_mut()
496 .update(text, range, version)
497 .map_err(SourceManagerError::InvalidContentUpdate)
498 }
499 SourceGroup::Unknown => Err(SourceManagerError::InvalidSourceId),
500 }
501 }
502
503 fn get(&self, id: SourceId) -> Result<Arc<SourceFile>, SourceManagerError> {
504 let manager = self.0.read();
505 manager.get(id)
506 }
507
508 fn get_by_uri(&self, uri: &FileName) -> Option<Arc<SourceFile>> {
509 let manager = self.0.read();
510 manager.get_by_uri(uri)
511 }
512
513 fn find(&self, uri: &FileName) -> Option<SourceId> {
514 let manager = self.0.read();
515 manager.find(uri)
516 }
517
518 fn file_line_col_to_span(&self, loc: FileLineCol) -> Option<SourceSpan> {
519 let manager = self.0.read();
520 manager.file_line_col_to_span(loc)
521 }
522
523 fn file_line_col(&self, span: SourceSpan) -> Result<FileLineCol, SourceManagerError> {
524 let manager = self.0.read();
525 manager.file_line_col(span)
526 }
527
528 fn location_to_span(&self, loc: Location) -> Option<SourceSpan> {
529 let manager = self.0.read();
530 manager.location_to_span(loc)
531 }
532
533 fn location(&self, span: SourceSpan) -> Result<Location, SourceManagerError> {
534 let manager = self.0.read();
535 manager.location(span)
536 }
537
538 fn source(&self, id: SourceId) -> Result<&str, SourceManagerError> {
539 let manager = self.0.read();
540 let ptr = manager.get(id).map(|file| file.as_str() as *const str)?;
541 drop(manager);
542 Ok(unsafe { &*ptr })
547 }
548
549 fn source_slice(&self, span: SourceSpan) -> Result<&str, SourceManagerError> {
550 self.source(span.source_id())?
551 .get(span.into_slice_index().into_range())
552 .ok_or(SourceManagerError::InvalidBounds)
553 }
554}
555
556#[cfg(test)]
557mod error_assertions {
558 use super::*;
559
560 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
562
563 fn _assert_source_manager_error_bounds(err: SourceManagerError) {
564 _assert_error_is_send_sync_static(err);
565 }
566}