1#![allow(unused)]
2
3use std::path::{Path, PathBuf};
4
5use memmap2::Mmap;
6
7use crate::{decode, extension, File, State};
8
9mod error {
10
11 #[derive(Debug, thiserror::Error)]
13 #[allow(missing_docs)]
14 pub enum Error {
15 #[error("An IO error occurred while opening the index")]
16 Io(#[from] std::io::Error),
17 #[error(transparent)]
18 Decode(#[from] crate::decode::Error),
19 #[error(transparent)]
20 LinkExtension(#[from] crate::extension::link::decode::Error),
21 }
22}
23
24pub use error::Error;
25
26impl File {
28 pub fn at_or_default(
33 path: impl Into<PathBuf>,
34 object_hash: git_hash::Kind,
35 options: decode::Options,
36 ) -> Result<Self, Error> {
37 let path = path.into();
38 Ok(match Self::at(&path, object_hash, options) {
39 Ok(f) => f,
40 Err(Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
41 File::from_state(State::new(object_hash), path)
42 }
43 Err(err) => return Err(err),
44 })
45 }
46
47 pub fn at(path: impl Into<PathBuf>, object_hash: git_hash::Kind, options: decode::Options) -> Result<Self, Error> {
49 let path = path.into();
50 let (data, mtime) = {
51 let file = std::fs::File::open(&path)?;
53 #[allow(unsafe_code)]
54 let data = unsafe { Mmap::map(&file)? };
55 (data, filetime::FileTime::from_last_modification_time(&file.metadata()?))
56 };
57
58 let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?;
59 let mut file = File {
60 state,
61 path,
62 checksum: Some(checksum),
63 };
64 if let Some(mut link) = file.link.take() {
65 link.dissolve_into(&mut file, object_hash, options)?;
66 }
67
68 Ok(file)
69 }
70
71 pub fn from_state(state: crate::State, path: impl Into<PathBuf>) -> Self {
75 File {
76 state,
77 path: path.into(),
78 checksum: None,
79 }
80 }
81}