summaryrefslogtreecommitdiff
path: root/src/file.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-06-28 10:35:44 +0200
committerLaurenz <laurmaedje@gmail.com>2023-06-28 10:36:53 +0200
commit04bffc4f12ff7dd85d25f5fd65506440287f879c (patch)
tree311a78d174f95c6e4733e3eb17a40f78744c3854 /src/file.rs
parent7b92bd7c340d9f9c094ed2fa57912049317d9b20 (diff)
Reintroduce `--root`
Diffstat (limited to 'src/file.rs')
-rw-r--r--src/file.rs50
1 files changed, 33 insertions, 17 deletions
diff --git a/src/file.rs b/src/file.rs
index a9d3c85e..1ee4cf09 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -29,28 +29,44 @@ type Pair = &'static (Option<PackageSpec>, 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<PackageSpec>, 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("<detached>")
+ 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}"),
}
}