From 04bffc4f12ff7dd85d25f5fd65506440287f879c Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 28 Jun 2023 10:35:44 +0200 Subject: Reintroduce `--root` --- src/eval/mod.rs | 3 +-- src/file.rs | 50 +++++++++++++++++++++++++++++++++----------------- src/util/mod.rs | 1 - 3 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 0805f9cc..fe28e3f3 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -1767,8 +1767,7 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult, PathBuf); /// Identifies a file. /// -/// This type is interned and thus cheap to clone, compare, and hash. +/// This type is globally interned and thus cheap to copy, compare, and hash. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct FileId(u16); impl FileId { /// Create a new interned file specification. /// - /// Normalizes the path before interning. + /// The path must start with a `/` or this function will panic. + /// Note that the path is normalized before interning. + #[track_caller] pub fn new(package: Option, path: &Path) -> Self { + assert_eq!( + path.components().next(), + Some(std::path::Component::RootDir), + "file path must be absolute within project or package: {}", + path.display(), + ); + + // Try to find an existing entry that we can reuse. let pair = (package, path.normalize()); + if let Some(&id) = INTERNER.read().unwrap().to_id.get(&pair) { + return id; + } + let mut interner = INTERNER.write().unwrap(); - interner.to_id.get(&pair).copied().unwrap_or_else(|| { - let leaked = Box::leak(Box::new(pair)); - let len = interner.from_id.len(); - if len >= usize::from(u16::MAX) { - panic!("too many file specifications"); - } - let id = FileId(len as u16); - interner.to_id.insert(leaked, id); - interner.from_id.push(leaked); - id - }) + let len = interner.from_id.len(); + if len >= usize::from(u16::MAX) { + panic!("too many file specifications"); + } + + // Create a new entry forever by leaking the pair. We can't leak more + // than 2^16 pair (and typically will leak a lot less), so its not a + // big deal. + let id = FileId(len as u16); + let leaked = Box::leak(Box::new(pair)); + interner.to_id.insert(leaked, id); + interner.from_id.push(leaked); + id } /// Get an id that does not identify any real file. @@ -72,11 +88,11 @@ impl FileId { } } - /// The normalized path to the file (within the package if there's a - /// package). + /// The absolute and normalized path to the file _within_ the project or + /// package. pub fn path(&self) -> &'static Path { if self.is_detached() { - Path::new("") + Path::new("/detached.typ") } else { &self.pair().1 } @@ -117,7 +133,7 @@ impl Display for FileId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let path = self.path().display(); match self.package() { - Some(package) => write!(f, "{package}/{path}"), + Some(package) => write!(f, "{package}{path}"), None => write!(f, "{path}"), } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 78c7bedf..05914b04 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -140,7 +140,6 @@ impl PathExt for Path { match component { Component::CurDir => {} Component::ParentDir => match out.components().next_back() { - Some(Component::RootDir) => {} Some(Component::Normal(_)) => { out.pop(); } -- cgit v1.2.3