1use std::hash::{DefaultHasher, Hash, Hasher};
2
3#[derive(Debug, Clone, Default)]
4pub struct FileId {
5 pub path: Option<String>,
6 pub content: Option<Vec<u8>>,
7 pub content_hash: u64,
8}
9
10impl FileId {
11 pub fn new_path(path: String) -> std::io::Result<Self> {
12 let content = std::fs::read(&path)?;
13
14 let mut hasher = DefaultHasher::new();
15 content.hash(&mut hasher);
16 let content_hash = hasher.finish();
17
18 Ok(FileId {
19 path: Some(path),
20 content: Some(content),
21 content_hash,
22 })
23 }
24
25 pub fn new_content(content: Vec<u8>) -> Self {
26 let mut hasher = DefaultHasher::new();
27 hasher.write(&content);
28 let content_hash = hasher.finish();
29
30 FileId {
31 path: None,
32 content: Some(content),
33 content_hash,
34 }
35 }
36
37 pub fn get_text(&self, start_byte: usize, end_byte: usize) -> Option<String> {
38 let content_bytes = self.content.as_ref()?;
39
40 if start_byte > end_byte
41 || start_byte > content_bytes.len()
42 || end_byte > content_bytes.len()
43 {
44 return None;
45 }
46
47 let slice = &content_bytes[start_byte..end_byte];
48 Some(String::from_utf8_lossy(slice).into_owned())
49 }
50
51 pub fn get_full_text(&self) -> Option<String> {
52 let content_bytes = self.content.as_ref()?;
53 Some(String::from_utf8_lossy(content_bytes).into_owned())
54 }
55}
56
57#[derive(Debug, Clone, Default)]
58pub struct File {
59 pub file: FileId,
61}
62
63impl File {
64 pub fn new_source(source: Vec<u8>) -> Self {
65 File {
66 file: FileId::new_content(source),
67 }
68 }
69
70 pub fn new_file(file: String) -> std::io::Result<Self> {
71 Ok(File {
72 file: FileId::new_path(file)?,
73 })
74 }
75
76 pub fn content(&self) -> Vec<u8> {
77 self.file.content.as_ref().unwrap().to_vec()
78 }
79
80 pub fn get_text(&self, start: usize, end: usize) -> String {
81 self.file.get_text(start, end).unwrap()
82 }
83
84 pub fn opt_get_text(&self, start: usize, end: usize) -> Option<String> {
85 self.file.get_text(start, end)
86 }
87
88 pub fn path(&self) -> Option<&str> {
89 self.file.path.as_deref()
90 }
91}