skeleton continues

This commit is contained in:
Qyriad 2026-01-27 17:20:04 +01:00
parent bcd11513ef
commit e5d0bdf0c0
5 changed files with 161 additions and 101 deletions

View file

@ -1,12 +1,16 @@
use std::{
hash::{Hash, Hasher},
sync::{Arc, LazyLock},
hash::Hash,
io::{BufRead, BufReader},
ops::{Deref, DerefMut},
sync::{Arc, Mutex, MutexGuard, OnceLock, PoisonError},
};
use crate::Line;
use crate::color::{ANSI_CYAN, ANSI_GREEN, ANSI_MAGENTA, ANSI_RESET};
#[allow(unused_imports)]
use crate::prelude::*;
use crate::color::{ANSI_CYAN, ANSI_RESET};
use fs_err::OpenOptions;
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct SourceLine {
@ -17,7 +21,13 @@ pub struct SourceLine {
impl Display for SourceLine {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "line {:03}: `{ANSI_CYAN}{}{ANSI_RESET}`", self.line.linenr(), self.text.trim())
write!(
f,
"{ANSI_MAGENTA}{}{ANSI_RESET}:{ANSI_GREEN}{}{ANSI_RESET}: `{ANSI_CYAN}{}{ANSI_RESET}`",
self.path.display(),
self.line.linenr(),
self.text.trim(),
)
}
}
@ -29,31 +39,64 @@ pub struct SourcePath {
#[derive(Debug, Clone)]
pub struct SourceFile {
path: Arc<Path>,
file: Arc<File>,
file: Arc<Mutex<File>>,
lines: Arc<OnceLock<Vec<SourceLine>>>,
}
impl SourceFile {
pub fn open_from(path: Arc<Path>, options: OpenOptions) -> Result<Self, IoError> {
let file = Arc::new(Mutex::new(options.open(&*path)?));
Ok(Self {
path,
file,
lines: Arc::new(OnceLock::new()),
})
}
pub fn buf_reader(&mut self) -> Result<BufReader<&mut File>, IoError> {
let file_mut = Arc::get_mut(&mut self.file)
.unwrap_or_else(|| panic!("'File' for {} has existing handle", self.path.display()))
.get_mut()
.unwrap_or_else(|e| {
panic!("'File' for {} was mutex-poisoned: {e}", self.path.display())
});
let reader = BufReader::new(file_mut);
Ok(reader)
}
pub fn lines(&self) -> Result<&[SourceLine], IoError> {
if let Some(lines) = self.lines.get() {
return Ok(lines);
}
let lines = BufReader::new(&*self.file.lock().unwrap())
.lines()
.enumerate()
.map(|(index, line_res)| {
line_res.map(|line| SourceLine {
line: Line::from_index(index as u64),
path: Arc::clone(&self.path),
text: Arc::from(line),
})
})
.collect::<Result<Vec<SourceLine>, IoError>>()?;
// Mutex should have dropped by now.
debug_assert!(self.file.try_lock().is_ok());
self.lines.set(lines).unwrap();
Ok(self.lines.get().unwrap().as_slice())
}
pub fn path(&self) -> Arc<Path> {
Arc::clone(&self.path)
}
}
impl PartialEq for SourceFile {
fn eq(&self, other: &Self) -> bool {
let paths_match = *self.path == *other.path;
if paths_match && self.file.as_raw_fd() != other.file.as_raw_fd() {
todo!("handle the case where source file paths match but FD numbers don't");
}
paths_match
*self.path == *other.path
}
}
impl Hash for SourceFile {
fn hash<H: Hasher>(&self, state: &mut H) {
self.path.hash(state);
self.file.as_raw_fd().hash(state);
}
}
#[derive(Debug, Clone, PartialEq, Hash)]
enum SourceInner {
Path(SourcePath),
File(SourceFile),
}
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct Source(SourceInner);