git_ref/store/packed/
buffer.rs1use crate::store_impl::packed;
2
3impl AsRef<[u8]> for packed::Buffer {
4 fn as_ref(&self) -> &[u8] {
5 &self.data.as_ref()[self.offset..]
6 }
7}
8
9impl AsRef<[u8]> for packed::Backing {
10 fn as_ref(&self) -> &[u8] {
11 match self {
12 packed::Backing::InMemory(data) => data,
13 packed::Backing::Mapped(map) => map,
14 }
15 }
16}
17
18pub mod open {
20 use std::path::PathBuf;
21
22 use memmap2::Mmap;
23
24 use crate::store_impl::packed;
25
26 impl packed::Buffer {
28 pub fn open(path: impl Into<PathBuf>, use_memory_map_if_larger_than_bytes: u64) -> Result<Self, Error> {
33 let path = path.into();
34 let (backing, offset) = {
35 let backing = if std::fs::metadata(&path)?.len() <= use_memory_map_if_larger_than_bytes {
36 packed::Backing::InMemory(std::fs::read(&path)?)
37 } else {
38 packed::Backing::Mapped(
39 #[allow(unsafe_code)]
41 unsafe {
42 Mmap::map(&std::fs::File::open(&path)?)?
43 },
44 )
45 };
46
47 let (offset, sorted) = {
48 let data = backing.as_ref();
49 if *data.first().unwrap_or(&b' ') == b'#' {
50 let (records, header) = packed::decode::header::<()>(data).map_err(|_| Error::HeaderParsing)?;
51 let offset = records.as_ptr() as usize - data.as_ptr() as usize;
52 (offset, header.sorted)
53 } else {
54 (0, false)
55 }
56 };
57
58 if !sorted {
59 let mut entries = packed::Iter::new(&backing.as_ref()[offset..])?.collect::<Result<Vec<_>, _>>()?;
61 entries.sort_by_key(|e| e.name.as_bstr());
62 let mut serialized = Vec::<u8>::new();
63 for entry in entries {
64 serialized.extend_from_slice(entry.target);
65 serialized.push(b' ');
66 serialized.extend_from_slice(entry.name.as_bstr());
67 serialized.push(b'\n');
68 if let Some(object) = entry.object {
69 serialized.push(b'^');
70 serialized.extend_from_slice(object);
71 serialized.push(b'\n');
72 }
73 }
74 (Backing::InMemory(serialized), 0)
75 } else {
76 (backing, offset)
77 }
78 };
79 Ok(packed::Buffer {
80 offset,
81 data: backing,
82 path,
83 })
84 }
85 }
86
87 mod error {
88 use crate::packed;
89
90 #[derive(Debug, thiserror::Error)]
92 #[allow(missing_docs)]
93 pub enum Error {
94 #[error("The packed-refs file did not have a header or wasn't sorted and could not be iterated")]
95 Iter(#[from] packed::iter::Error),
96 #[error("The header could not be parsed, even though first line started with '#'")]
97 HeaderParsing,
98 #[error("The buffer could not be opened or read")]
99 Io(#[from] std::io::Error),
100 }
101 }
102 pub use error::Error;
103
104 use crate::packed::Backing;
105}