gix_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 crate::store_impl::packed;
23
24 impl packed::Buffer {
26 fn open_with_backing(
27 backing: packed::Backing,
28 path: PathBuf,
29 hash_kind: gix_hash::Kind,
30 ) -> Result<Self, Error> {
31 let (backing, offset) = {
32 let (offset, sorted) = {
33 let mut input = backing.as_ref();
34 if *input.first().unwrap_or(&b' ') == b'#' {
35 let header = packed::decode::header(&mut input).map_err(|_| Error::HeaderParsing)?;
36 let offset = backing.as_ref().len() - input.len();
37 (offset, header.sorted)
38 } else {
39 (0, false)
40 }
41 };
42
43 if !sorted {
44 let mut entries =
46 packed::Iter::new(&backing.as_ref()[offset..], hash_kind)?.collect::<Result<Vec<_>, _>>()?;
47 entries.sort_by_key(|e| e.name.as_bstr());
48 let mut serialized = Vec::<u8>::new();
49 for entry in entries {
50 serialized.extend_from_slice(entry.target);
51 serialized.push(b' ');
52 serialized.extend_from_slice(entry.name.as_bstr());
53 serialized.push(b'\n');
54 if let Some(object) = entry.object {
55 serialized.push(b'^');
56 serialized.extend_from_slice(object);
57 serialized.push(b'\n');
58 }
59 }
60 (Backing::InMemory(serialized), 0)
61 } else {
62 (backing, offset)
63 }
64 };
65 Ok(packed::Buffer {
66 offset,
67 data: backing,
68 path,
69 hash_kind,
70 })
71 }
72
73 pub fn open(
79 path: PathBuf,
80 use_memory_map_if_larger_than_bytes: u64,
81 hash_kind: gix_hash::Kind,
82 ) -> Result<Self, Error> {
83 let backing = if std::fs::metadata(&path)?.len() <= use_memory_map_if_larger_than_bytes {
84 packed::Backing::InMemory(std::fs::read(&path)?)
85 } else {
86 packed::Backing::Mapped(
87 #[allow(unsafe_code)]
89 unsafe {
90 memmap2::MmapOptions::new().map_copy_read_only(&std::fs::File::open(&path)?)?
91 },
92 )
93 };
94 Self::open_with_backing(backing, path, hash_kind)
95 }
96
97 pub fn from_bytes(bytes: &[u8], hash_kind: gix_hash::Kind) -> Result<Self, Error> {
103 let backing = packed::Backing::InMemory(bytes.into());
104 Self::open_with_backing(backing, PathBuf::from("<memory>"), hash_kind)
105 }
106 }
107
108 mod error {
109 use crate::packed;
110
111 #[derive(Debug, thiserror::Error)]
113 #[allow(missing_docs)]
114 pub enum Error {
115 #[error("The packed-refs file did not have a header or wasn't sorted and could not be iterated")]
116 Iter(#[from] packed::iter::Error),
117 #[error("The header could not be parsed, even though first line started with '#'")]
118 HeaderParsing,
119 #[error("The buffer could not be opened or read")]
120 Io(#[from] std::io::Error),
121 }
122 }
123 pub use error::Error;
124
125 use crate::packed::Backing;
126}