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