diff options
Diffstat (limited to 'vendor/gix-index/src/lib.rs')
-rw-r--r-- | vendor/gix-index/src/lib.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/vendor/gix-index/src/lib.rs b/vendor/gix-index/src/lib.rs new file mode 100644 index 000000000..d8451c545 --- /dev/null +++ b/vendor/gix-index/src/lib.rs @@ -0,0 +1,201 @@ +//! ## Feature Flags +#![cfg_attr( + feature = "document-features", + cfg_attr(doc, doc = ::document_features::document_features!()) +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![deny(unsafe_code, missing_docs, rust_2018_idioms)] + +use std::{ops::Range, path::PathBuf}; + +use filetime::FileTime; +pub use gix_hash as hash; + +/// +pub mod file; + +/// +pub mod extension; + +/// +pub mod entry; + +mod access; + +mod init; + +/// +pub mod decode; + +/// +pub mod verify; + +/// +pub mod write; + +/// All known versions of a git index file. +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +pub enum Version { + /// Supports entries and various extensions. + V2 = 2, + /// Adds support for additional flags for each entry, called extended entries. + V3 = 3, + /// Supports deltified entry paths. + V4 = 4, +} + +/// An entry in the index, identifying a non-tree item on disk. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Entry { + /// The filesystem stat information for the file on disk. + pub stat: entry::Stat, + /// The object id for this entry's ODB representation (assuming it's up-to-date with it). + pub id: gix_hash::ObjectId, + /// Additional flags for use in algorithms and for efficiently storing stage information. + pub flags: entry::Flags, + /// The kind of item this entry represents - it's not all blobs in the index anymore. + pub mode: entry::Mode, + /// The range to lookup in the path backing to obtain the entry path relative to the repository. + /// This costs additional memory but is probably worth it given that paths can stay in one big allocation. + path: Range<usize>, +} + +/// An index file whose state was read from a file on disk. +#[derive(Clone)] +pub struct File { + /// The state containing the actual index data. + pub(crate) state: State, + /// The path from which the index was read or to which it is supposed to be written. + pub(crate) path: PathBuf, + /// The checksum of all bytes prior to the checksum itself. + pub(crate) checksum: Option<gix_hash::ObjectId>, +} + +/// The type to use and store paths to all entries. +pub type PathStorage = Vec<u8>; +/// The type to use and store paths to all entries, as reference +pub type PathStorageRef = [u8]; + +/// An in-memory cache of a fully parsed git index file. +/// +/// As opposed to a snapshot, it's meant to be altered and eventually be written back to disk or converted into a tree. +/// We treat index and its state synonymous. +#[derive(Clone)] +pub struct State { + /// The kind of object hash used when storing the underlying file. + /// + /// Empty states for example won't have a single object id, so deduction of the hash used isn't always possible. + object_hash: gix_hash::Kind, + /// The time at which the state was created, indicating its freshness compared to other files on disk. + /// + /// Note that on platforms that only have a precisions of a second for this time, we will treat all entries with the + /// same timestamp as this as potentially changed, checking more thoroughly if a change actually happened. + #[allow(dead_code)] + timestamp: FileTime, + version: Version, + entries: Vec<Entry>, + /// A memory area keeping all index paths, in full length, independently of the index version. + path_backing: PathStorage, + /// True if one entry in the index has a special marker mode + is_sparse: bool, + + // Extensions + tree: Option<extension::Tree>, + link: Option<extension::Link>, + resolve_undo: Option<extension::resolve_undo::Paths>, + untracked: Option<extension::UntrackedCache>, + fs_monitor: Option<extension::FsMonitor>, +} + +mod impls { + use std::fmt::{Debug, Formatter}; + + use crate::State; + + impl Debug for State { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + for entry in &self.entries { + writeln!( + f, + "{} {}{:?} {} {}", + match entry.flags.stage() { + 0 => "BASE ", + 1 => "OURS ", + 2 => "THEIRS ", + _ => "UNKNOWN", + }, + if entry.flags.is_empty() { + "".to_string() + } else { + format!("{:?} ", entry.flags) + }, + entry.mode, + entry.id, + entry.path(self) + )?; + } + Ok(()) + } + } +} + +pub(crate) mod util { + use std::convert::TryInto; + + #[inline] + pub fn var_int(data: &[u8]) -> Option<(u64, &[u8])> { + let (num, consumed) = gix_features::decode::leb64_from_read(data).ok()?; + let data = &data[consumed..]; + (num, data).into() + } + + #[inline] + pub fn read_u32(data: &[u8]) -> Option<(u32, &[u8])> { + split_at_pos(data, 4).map(|(num, data)| (u32::from_be_bytes(num.try_into().unwrap()), data)) + } + + #[inline] + pub fn read_u64(data: &[u8]) -> Option<(u64, &[u8])> { + split_at_pos(data, 8).map(|(num, data)| (u64::from_be_bytes(num.try_into().unwrap()), data)) + } + + #[inline] + pub fn from_be_u32(b: &[u8]) -> u32 { + u32::from_be_bytes(b.try_into().unwrap()) + } + + #[inline] + pub fn split_at_byte_exclusive(data: &[u8], byte: u8) -> Option<(&[u8], &[u8])> { + if data.len() < 2 { + return None; + } + data.iter().enumerate().find_map(|(idx, b)| { + (*b == byte).then(|| { + if idx == 0 { + (&[] as &[u8], &data[1..]) + } else { + let (a, b) = data.split_at(idx); + (a, &b[1..]) + } + }) + }) + } + + #[inline] + pub fn split_at_pos(data: &[u8], pos: usize) -> Option<(&[u8], &[u8])> { + if data.len() < pos { + return None; + } + data.split_at(pos).into() + } +} + +#[test] +fn size_of_entry() { + assert_eq!(std::mem::size_of::<crate::Entry>(), 80); + + // the reason we have our own time is half the size. + assert_eq!(std::mem::size_of::<crate::entry::Time>(), 8); + assert_eq!(std::mem::size_of::<filetime::FileTime>(), 16); +} |