use std::collections::HashMap;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct PathId(u32);
impl PathId {
pub const fn new(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Position {
pub line: u32,
pub column: u32,
pub byte_offset: u32,
}
impl Position {
pub const fn new(line: u32, column: u32, byte_offset: u32) -> Self {
Self {
line,
column,
byte_offset,
}
}
pub const fn zero() -> Self {
Self::new(1, 1, 0)
}
}
impl Default for Position {
fn default() -> Self {
Self::zero()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Loc {
pub path: PathId,
pub start: Position,
pub end: Position,
}
impl Loc {
pub fn point(path: PathId, pos: Position) -> Self {
Self {
path,
start: pos,
end: pos,
}
}
pub fn span(path: PathId, start: Position, end: Position) -> Self {
Self { path, start, end }
}
}
#[derive(Debug, Default, Clone)]
pub struct PathInterner {
paths: Vec<PathBuf>,
index: HashMap<PathBuf, PathId>,
}
impl PathInterner {
pub fn new() -> Self {
Self::default()
}
pub fn intern(&mut self, p: &Path) -> PathId {
if let Some(id) = self.index.get(p) {
return *id;
}
let id = PathId::new(u32::try_from(self.paths.len()).expect("path id overflow"));
let owned = p.to_path_buf();
self.paths.push(owned.clone());
self.index.insert(owned, id);
id
}
pub fn get(&self, id: PathId) -> Option<&Path> {
self.paths.get(id.as_u32() as usize).map(PathBuf::as_path)
}
pub fn len(&self) -> usize {
self.paths.len()
}
pub fn is_empty(&self) -> bool {
self.paths.is_empty()
}
}