From 55363ea650001b7717545b4d2968419707a3b8c6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 2 Aug 2022 09:23:33 +0800 Subject: [PATCH] feat: `State::entry_by_path_and_stage()` to find entries. (#427) --- git-index/src/access.rs | 17 ++++++++++++++++- git-index/src/entry.rs | 13 ++++++++----- git-index/src/lib.rs | 2 +- git-index/tests/index/file/access.rs | 14 +++++++++++--- git-index/tests/index/file/read.rs | 2 +- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/git-index/src/access.rs b/git-index/src/access.rs index c72fd75ad3..c2aae182cb 100644 --- a/git-index/src/access.rs +++ b/git-index/src/access.rs @@ -1,7 +1,8 @@ use bstr::{BStr, ByteSlice}; -use crate::{extension, Entry, PathStorage, State, Version}; +use crate::{entry, extension, Entry, PathStorage, State, Version}; +/// General information and entries impl State { pub fn version(&self) -> Version { self.version @@ -58,6 +59,20 @@ impl State { (e, path) }) } + + /// Find the entry index in [`entries()`][State::entries()] matching the given repository-relative + /// `path` and `stage`, or `None`. + /// + /// Use the index for accessing multiple stages if they exists, but at least the single matching entry. + pub fn entry_by_path_and_stage(&self, path: &BStr, stage: entry::Stage) -> Option { + self.entries + .binary_search_by(|e| e.path(self).cmp(path).then_with(|| e.stage().cmp(&stage))) + .ok() + } +} + +/// Extensions +impl State { pub fn tree(&self) -> Option<&extension::Tree> { self.tree.as_ref() } diff --git a/git-index/src/entry.rs b/git-index/src/entry.rs index be72ef7281..efc51aa353 100644 --- a/git-index/src/entry.rs +++ b/git-index/src/entry.rs @@ -1,5 +1,8 @@ use bitflags::bitflags; +/// The stage of an entry, one of 0 = base, 1 = ours, 2 = theirs +pub type Stage = u32; + bitflags! { pub struct Mode: u32 { /// directory (only used for sparse checkouts), equivalent to a tree @@ -106,12 +109,12 @@ bitflags! { } impl Flags { - pub fn stage(&self) -> u32 { + pub fn stage(&self) -> Stage { (*self & Flags::STAGE_MASK).bits >> 12 } } -#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Copy)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub struct Time { /// The amount of seconds elapsed since EPOCH @@ -120,7 +123,7 @@ pub struct Time { pub nsecs: u32, } -#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Copy)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub struct Stat { pub mtime: Time, @@ -136,7 +139,7 @@ pub struct Stat { mod access { use bstr::{BStr, ByteSlice}; - use crate::{Entry, State}; + use crate::{entry, Entry, State}; impl Entry { pub fn path<'a>(&self, state: &'a State) -> &'a BStr { @@ -147,7 +150,7 @@ mod access { (backing[self.path.clone()]).as_bstr() } - pub fn stage(&self) -> u32 { + pub fn stage(&self) -> entry::Stage { self.flags.stage() } } diff --git a/git-index/src/lib.rs b/git-index/src/lib.rs index c1b9699ddf..6089df58f4 100644 --- a/git-index/src/lib.rs +++ b/git-index/src/lib.rs @@ -37,7 +37,7 @@ pub enum Version { } /// An entry in the index, identifying a non-tree item on disk. -#[derive(Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Entry { pub stat: entry::Stat, pub id: git_hash::ObjectId, diff --git a/git-index/tests/index/file/access.rs b/git-index/tests/index/file/access.rs index 6f83a5d953..2e15c98bfd 100644 --- a/git-index/tests/index/file/access.rs +++ b/git-index/tests/index/file/access.rs @@ -1,5 +1,13 @@ +use crate::index::file::read; + #[test] -#[ignore] -fn entry_by_path() { - todo!() +fn entry_by_path_and_stage() { + let file = read::file("v4_more_files_IEOT"); + for entry in file.entries() { + let path = entry.path(&file); + assert_eq!( + file.entry_by_path_and_stage(path, 0).map(|idx| &file.entries()[idx]), + Some(entry) + ); + } } diff --git a/git-index/tests/index/file/read.rs b/git-index/tests/index/file/read.rs index c8c055934a..02356f4ce7 100644 --- a/git-index/tests/index/file/read.rs +++ b/git-index/tests/index/file/read.rs @@ -18,7 +18,7 @@ fn loose_file(name: &str) -> git_index::File { let file = git_index::File::at(path, git_index::decode::Options::default()).unwrap(); verify(file) } -fn file(name: &str) -> git_index::File { +pub(crate) fn file(name: &str) -> git_index::File { let file = git_index::File::at(crate::fixture_index_path(name), git_index::decode::Options::default()).unwrap(); verify(file) }