summaryrefslogtreecommitdiffstats
path: root/vendor/gix-config/src/file/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-config/src/file/util.rs')
-rw-r--r--vendor/gix-config/src/file/util.rs190
1 files changed, 190 insertions, 0 deletions
diff --git a/vendor/gix-config/src/file/util.rs b/vendor/gix-config/src/file/util.rs
new file mode 100644
index 000000000..5c60f1fd5
--- /dev/null
+++ b/vendor/gix-config/src/file/util.rs
@@ -0,0 +1,190 @@
+use std::{cmp::Ordering, collections::HashMap};
+
+use bstr::BStr;
+
+use crate::{
+ file::{self, SectionBodyIdsLut, SectionId},
+ lookup,
+ parse::section,
+ File,
+};
+
+/// Private helper functions
+impl<'event> File<'event> {
+ /// Adds a new section to the config file, returning the section id of the newly added section.
+ pub(crate) fn push_section_internal(&mut self, mut section: file::Section<'event>) -> SectionId {
+ let new_section_id = SectionId(self.section_id_counter);
+ section.id = new_section_id;
+ self.sections.insert(new_section_id, section);
+ let header = &self.sections[&new_section_id].header;
+ let lookup = self.section_lookup_tree.entry(header.name.clone()).or_default();
+
+ let mut found_node = false;
+ if let Some(subsection_name) = header.subsection_name.clone() {
+ for node in lookup.iter_mut() {
+ if let SectionBodyIdsLut::NonTerminal(subsections) = node {
+ found_node = true;
+ subsections
+ .entry(subsection_name.clone())
+ .or_default()
+ .push(new_section_id);
+ break;
+ }
+ }
+ if !found_node {
+ let mut map = HashMap::new();
+ map.insert(subsection_name, vec![new_section_id]);
+ lookup.push(SectionBodyIdsLut::NonTerminal(map));
+ }
+ } else {
+ for node in lookup.iter_mut() {
+ if let SectionBodyIdsLut::Terminal(vec) = node {
+ found_node = true;
+ vec.push(new_section_id);
+ break;
+ }
+ }
+ if !found_node {
+ lookup.push(SectionBodyIdsLut::Terminal(vec![new_section_id]));
+ }
+ }
+ self.section_order.push_back(new_section_id);
+ self.section_id_counter += 1;
+ new_section_id
+ }
+
+ /// Inserts `section` after the section that comes `before` it, and maintains correct ordering in all of our lookup structures.
+ pub(crate) fn insert_section_after(&mut self, mut section: file::Section<'event>, before: SectionId) -> SectionId {
+ let lookup_section_order = {
+ let section_order = &self.section_order;
+ move |section_id| {
+ section_order
+ .iter()
+ .enumerate()
+ .find_map(|(idx, id)| (*id == section_id).then_some(idx))
+ .expect("before-section exists")
+ }
+ };
+
+ let before_order = lookup_section_order(before);
+ let new_section_id = SectionId(self.section_id_counter);
+ section.id = new_section_id;
+ self.sections.insert(new_section_id, section);
+ let header = &self.sections[&new_section_id].header;
+ let lookup = self.section_lookup_tree.entry(header.name.clone()).or_default();
+
+ let mut found_node = false;
+ if let Some(subsection_name) = header.subsection_name.clone() {
+ for node in lookup.iter_mut() {
+ if let SectionBodyIdsLut::NonTerminal(subsections) = node {
+ found_node = true;
+ let sections_with_name_and_subsection_name =
+ subsections.entry(subsection_name.clone()).or_default();
+ let insert_pos = find_insert_pos_by_order(
+ sections_with_name_and_subsection_name,
+ before_order,
+ lookup_section_order,
+ );
+ sections_with_name_and_subsection_name.insert(insert_pos, new_section_id);
+ break;
+ }
+ }
+ if !found_node {
+ let mut map = HashMap::new();
+ map.insert(subsection_name, vec![new_section_id]);
+ lookup.push(SectionBodyIdsLut::NonTerminal(map));
+ }
+ } else {
+ for node in lookup.iter_mut() {
+ if let SectionBodyIdsLut::Terminal(sections_with_name) = node {
+ found_node = true;
+ let insert_pos = find_insert_pos_by_order(sections_with_name, before_order, lookup_section_order);
+ sections_with_name.insert(insert_pos, new_section_id);
+ break;
+ }
+ }
+ if !found_node {
+ lookup.push(SectionBodyIdsLut::Terminal(vec![new_section_id]));
+ }
+ }
+
+ self.section_order.insert(before_order + 1, new_section_id);
+ self.section_id_counter += 1;
+ new_section_id
+ }
+
+ /// Returns the mapping between section and subsection name to section ids.
+ pub(crate) fn section_ids_by_name_and_subname<'a>(
+ &'a self,
+ section_name: &'a str,
+ subsection_name: Option<&BStr>,
+ ) -> Result<impl Iterator<Item = SectionId> + ExactSizeIterator + DoubleEndedIterator + '_, lookup::existing::Error>
+ {
+ let section_name = section::Name::from_str_unchecked(section_name);
+ let section_ids = self
+ .section_lookup_tree
+ .get(&section_name)
+ .ok_or(lookup::existing::Error::SectionMissing)?;
+ let mut maybe_ids = None;
+ if let Some(subsection_name) = subsection_name {
+ for node in section_ids {
+ if let SectionBodyIdsLut::NonTerminal(subsection_lookup) = node {
+ maybe_ids = subsection_lookup.get(subsection_name).map(|v| v.iter().copied());
+ break;
+ }
+ }
+ } else {
+ for node in section_ids {
+ if let SectionBodyIdsLut::Terminal(subsection_lookup) = node {
+ maybe_ids = Some(subsection_lookup.iter().copied());
+ break;
+ }
+ }
+ }
+ maybe_ids.ok_or(lookup::existing::Error::SubSectionMissing)
+ }
+
+ pub(crate) fn section_ids_by_name<'a>(
+ &'a self,
+ section_name: &'a str,
+ ) -> Result<impl Iterator<Item = SectionId> + '_, lookup::existing::Error> {
+ let section_name = section::Name::from_str_unchecked(section_name);
+ match self.section_lookup_tree.get(&section_name) {
+ Some(lookup) => {
+ let mut lut = Vec::with_capacity(self.section_order.len());
+ for node in lookup {
+ match node {
+ SectionBodyIdsLut::Terminal(v) => lut.extend(v.iter().copied()),
+ SectionBodyIdsLut::NonTerminal(v) => lut.extend(v.values().flatten().copied()),
+ }
+ }
+
+ Ok(self.section_order.iter().filter(move |a| lut.contains(a)).copied())
+ }
+ None => Err(lookup::existing::Error::SectionMissing),
+ }
+ }
+}
+
+fn find_insert_pos_by_order(
+ sections_with_name: &[SectionId],
+ before_order: usize,
+ lookup_section_order: impl Fn(SectionId) -> usize,
+) -> usize {
+ let mut insert_pos = sections_with_name.len(); // push back by default
+ for (idx, candidate_id) in sections_with_name.iter().enumerate() {
+ let candidate_order = lookup_section_order(*candidate_id);
+ match candidate_order.cmp(&before_order) {
+ Ordering::Less => {}
+ Ordering::Equal => {
+ insert_pos = idx + 1; // insert right after this one
+ break;
+ }
+ Ordering::Greater => {
+ insert_pos = idx; // insert before this one
+ break;
+ }
+ }
+ }
+ insert_pos
+}