]> git.proxmox.com Git - rustc.git/blob - vendor/gix-config/src/file/util.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / gix-config / src / file / util.rs
1 use std::{cmp::Ordering, collections::HashMap};
2
3 use bstr::BStr;
4
5 use crate::{
6 file::{self, SectionBodyIdsLut, SectionId},
7 lookup,
8 parse::section,
9 File,
10 };
11
12 /// Private helper functions
13 impl<'event> File<'event> {
14 /// Adds a new section to the config file, returning the section id of the newly added section.
15 pub(crate) fn push_section_internal(&mut self, mut section: file::Section<'event>) -> SectionId {
16 let new_section_id = SectionId(self.section_id_counter);
17 section.id = new_section_id;
18 self.sections.insert(new_section_id, section);
19 let header = &self.sections[&new_section_id].header;
20 let lookup = self.section_lookup_tree.entry(header.name.clone()).or_default();
21
22 let mut found_node = false;
23 if let Some(subsection_name) = header.subsection_name.clone() {
24 for node in lookup.iter_mut() {
25 if let SectionBodyIdsLut::NonTerminal(subsections) = node {
26 found_node = true;
27 subsections
28 .entry(subsection_name.clone())
29 .or_default()
30 .push(new_section_id);
31 break;
32 }
33 }
34 if !found_node {
35 let mut map = HashMap::new();
36 map.insert(subsection_name, vec![new_section_id]);
37 lookup.push(SectionBodyIdsLut::NonTerminal(map));
38 }
39 } else {
40 for node in lookup.iter_mut() {
41 if let SectionBodyIdsLut::Terminal(vec) = node {
42 found_node = true;
43 vec.push(new_section_id);
44 break;
45 }
46 }
47 if !found_node {
48 lookup.push(SectionBodyIdsLut::Terminal(vec![new_section_id]));
49 }
50 }
51 self.section_order.push_back(new_section_id);
52 self.section_id_counter += 1;
53 new_section_id
54 }
55
56 /// Inserts `section` after the section that comes `before` it, and maintains correct ordering in all of our lookup structures.
57 pub(crate) fn insert_section_after(&mut self, mut section: file::Section<'event>, before: SectionId) -> SectionId {
58 let lookup_section_order = {
59 let section_order = &self.section_order;
60 move |section_id| {
61 section_order
62 .iter()
63 .enumerate()
64 .find_map(|(idx, id)| (*id == section_id).then_some(idx))
65 .expect("before-section exists")
66 }
67 };
68
69 let before_order = lookup_section_order(before);
70 let new_section_id = SectionId(self.section_id_counter);
71 section.id = new_section_id;
72 self.sections.insert(new_section_id, section);
73 let header = &self.sections[&new_section_id].header;
74 let lookup = self.section_lookup_tree.entry(header.name.clone()).or_default();
75
76 let mut found_node = false;
77 if let Some(subsection_name) = header.subsection_name.clone() {
78 for node in lookup.iter_mut() {
79 if let SectionBodyIdsLut::NonTerminal(subsections) = node {
80 found_node = true;
81 let sections_with_name_and_subsection_name =
82 subsections.entry(subsection_name.clone()).or_default();
83 let insert_pos = find_insert_pos_by_order(
84 sections_with_name_and_subsection_name,
85 before_order,
86 lookup_section_order,
87 );
88 sections_with_name_and_subsection_name.insert(insert_pos, new_section_id);
89 break;
90 }
91 }
92 if !found_node {
93 let mut map = HashMap::new();
94 map.insert(subsection_name, vec![new_section_id]);
95 lookup.push(SectionBodyIdsLut::NonTerminal(map));
96 }
97 } else {
98 for node in lookup.iter_mut() {
99 if let SectionBodyIdsLut::Terminal(sections_with_name) = node {
100 found_node = true;
101 let insert_pos = find_insert_pos_by_order(sections_with_name, before_order, lookup_section_order);
102 sections_with_name.insert(insert_pos, new_section_id);
103 break;
104 }
105 }
106 if !found_node {
107 lookup.push(SectionBodyIdsLut::Terminal(vec![new_section_id]));
108 }
109 }
110
111 self.section_order.insert(before_order + 1, new_section_id);
112 self.section_id_counter += 1;
113 new_section_id
114 }
115
116 /// Returns the mapping between section and subsection name to section ids.
117 pub(crate) fn section_ids_by_name_and_subname<'a>(
118 &'a self,
119 section_name: &'a str,
120 subsection_name: Option<&BStr>,
121 ) -> Result<impl Iterator<Item = SectionId> + ExactSizeIterator + DoubleEndedIterator + '_, lookup::existing::Error>
122 {
123 let section_name = section::Name::from_str_unchecked(section_name);
124 let section_ids = self
125 .section_lookup_tree
126 .get(&section_name)
127 .ok_or(lookup::existing::Error::SectionMissing)?;
128 let mut maybe_ids = None;
129 if let Some(subsection_name) = subsection_name {
130 for node in section_ids {
131 if let SectionBodyIdsLut::NonTerminal(subsection_lookup) = node {
132 maybe_ids = subsection_lookup.get(subsection_name).map(|v| v.iter().copied());
133 break;
134 }
135 }
136 } else {
137 for node in section_ids {
138 if let SectionBodyIdsLut::Terminal(subsection_lookup) = node {
139 maybe_ids = Some(subsection_lookup.iter().copied());
140 break;
141 }
142 }
143 }
144 maybe_ids.ok_or(lookup::existing::Error::SubSectionMissing)
145 }
146
147 pub(crate) fn section_ids_by_name<'a>(
148 &'a self,
149 section_name: &'a str,
150 ) -> Result<impl Iterator<Item = SectionId> + '_, lookup::existing::Error> {
151 let section_name = section::Name::from_str_unchecked(section_name);
152 match self.section_lookup_tree.get(&section_name) {
153 Some(lookup) => {
154 let mut lut = Vec::with_capacity(self.section_order.len());
155 for node in lookup {
156 match node {
157 SectionBodyIdsLut::Terminal(v) => lut.extend(v.iter().copied()),
158 SectionBodyIdsLut::NonTerminal(v) => lut.extend(v.values().flatten().copied()),
159 }
160 }
161
162 Ok(self.section_order.iter().filter(move |a| lut.contains(a)).copied())
163 }
164 None => Err(lookup::existing::Error::SectionMissing),
165 }
166 }
167 }
168
169 fn find_insert_pos_by_order(
170 sections_with_name: &[SectionId],
171 before_order: usize,
172 lookup_section_order: impl Fn(SectionId) -> usize,
173 ) -> usize {
174 let mut insert_pos = sections_with_name.len(); // push back by default
175 for (idx, candidate_id) in sections_with_name.iter().enumerate() {
176 let candidate_order = lookup_section_order(*candidate_id);
177 match candidate_order.cmp(&before_order) {
178 Ordering::Less => {}
179 Ordering::Equal => {
180 insert_pos = idx + 1; // insert right after this one
181 break;
182 }
183 Ordering::Greater => {
184 insert_pos = idx; // insert before this one
185 break;
186 }
187 }
188 }
189 insert_pos
190 }