#![allow(missing_docs)]
use std::path::{Path, PathBuf};
use bstr::{BStr, ByteSlice};
use super::Stack;
use crate::PathIdMapping;
#[derive(Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Statistics {
pub platforms: usize,
pub delegate: delegate::Statistics,
#[cfg(feature = "attributes")]
pub attributes: state::attributes::Statistics,
pub ignore: state::ignore::Statistics,
}
#[derive(Clone)]
pub enum State {
#[cfg(feature = "attributes")]
CreateDirectoryAndAttributesStack {
unlink_on_collision: bool,
validate: gix_validate::path::component::Options,
attributes: state::Attributes,
},
#[cfg(feature = "attributes")]
AttributesAndIgnoreStack {
attributes: state::Attributes,
ignore: state::Ignore,
},
#[cfg(feature = "attributes")]
AttributesStack(state::Attributes),
IgnoreStack(state::Ignore),
}
#[must_use]
pub struct Platform<'a> {
parent: &'a Stack,
is_dir: Option<bool>,
}
impl Stack {
pub fn new(
worktree_root: impl Into<PathBuf>,
state: State,
case: gix_glob::pattern::Case,
buf: Vec<u8>,
id_mappings: Vec<PathIdMapping>,
) -> Self {
let root = worktree_root.into();
Stack {
stack: gix_fs::Stack::new(root),
state,
case,
buf,
id_mappings,
statistics: Statistics::default(),
}
}
pub fn from_state_and_ignore_case(
root: impl Into<PathBuf>,
ignore_case: bool,
state: State,
index: &gix_index::State,
path_backing: &gix_index::PathStorageRef,
) -> Self {
let case = if ignore_case {
gix_glob::pattern::Case::Fold
} else {
gix_glob::pattern::Case::Sensitive
};
let attribute_files = state.id_mappings_from_index(index, path_backing, case);
Stack::new(root, state, case, Vec::with_capacity(512), attribute_files)
}
}
impl Stack {
pub fn at_path(
&mut self,
relative: impl ToNormalPathComponents,
mode: Option<gix_index::entry::Mode>,
objects: &dyn gix_object::Find,
) -> std::io::Result<Platform<'_>> {
self.statistics.platforms += 1;
let mut delegate = StackDelegate {
state: &mut self.state,
buf: &mut self.buf,
mode,
id_mappings: &self.id_mappings,
objects,
case: self.case,
statistics: &mut self.statistics,
};
self.stack.make_relative_path_current(relative, &mut delegate)?;
Ok(Platform {
parent: self,
is_dir: mode_is_dir(mode),
})
}
pub fn at_entry<'r>(
&mut self,
relative: impl Into<&'r BStr>,
mode: Option<gix_index::entry::Mode>,
objects: &dyn gix_object::Find,
) -> std::io::Result<Platform<'_>> {
let relative = relative.into();
self.at_path(
relative,
mode.or_else(|| relative.ends_with_str("/").then_some(gix_index::entry::Mode::DIR)),
objects,
)
}
}
fn mode_is_dir(mode: Option<gix_index::entry::Mode>) -> Option<bool> {
mode.map(|m|
m.is_sparse() || m.is_submodule())
}
impl Stack {
pub fn take_statistics(&mut self) -> Statistics {
std::mem::take(&mut self.statistics)
}
pub fn state_mut(&mut self) -> &mut State {
&mut self.state
}
pub fn set_case(&mut self, case: gix_glob::pattern::Case) -> &mut Self {
self.case = case;
self
}
}
impl Stack {
pub fn statistics(&self) -> &Statistics {
&self.statistics
}
pub fn state(&self) -> &State {
&self.state
}
pub fn base(&self) -> &Path {
self.stack.root()
}
}
pub mod delegate;
use delegate::StackDelegate;
use gix_fs::stack::ToNormalPathComponents;
mod platform;
pub mod state;