1use std::{fs::File, io::Read, path::Path};
2
3use tinymist_std::ReadAllOnce;
4use typst::diag::{FileError, FileResult};
5
6use crate::{Bytes, PathAccessModel};
7
8#[derive(Debug, Clone, Copy)]
11pub struct SystemAccessModel;
12
13impl SystemAccessModel {
14 fn stat(&self, src: &Path) -> std::io::Result<SystemFileMeta> {
15 let meta = std::fs::metadata(src)?;
16 Ok(SystemFileMeta {
17 is_dir: meta.is_dir(),
18 })
19 }
20}
21
22impl PathAccessModel for SystemAccessModel {
23 fn content(&self, src: &Path) -> FileResult<Bytes> {
24 let f = |e| FileError::from_io(e, src);
25 let mut buf = Vec::<u8>::new();
26
27 let meta = self.stat(src).map_err(f)?;
28
29 if meta.is_dir {
30 return Err(FileError::IsDirectory);
31 }
32
33 std::fs::File::open(src)
34 .map_err(f)?
35 .read_to_end(&mut buf)
36 .map_err(f)?;
37 Ok(Bytes::new(buf))
38 }
39}
40
41#[derive(Debug)]
45pub struct LazyFile {
46 path: std::path::PathBuf,
47 file: Option<std::io::Result<File>>,
48}
49
50impl LazyFile {
51 pub fn new(path: std::path::PathBuf) -> Self {
53 Self { path, file: None }
54 }
55}
56
57impl ReadAllOnce for LazyFile {
58 fn read_all(mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
59 let mut file = self.file.get_or_insert_with(|| File::open(&self.path));
60 let Ok(file) = &mut file else {
61 let err = file.as_ref().unwrap_err();
62 return Err(std::io::Error::new(err.kind(), err.to_string()));
64 };
65
66 file.read_to_end(buf)
67 }
68}
69
70#[derive(Debug, Clone, Copy)]
72pub struct SystemFileMeta {
73 is_dir: bool,
74}