1use std::{cmp::Ordering, collections::HashMap};
2
3use bstr::BStr;
4
5use crate::{
6 file::{self, SectionBodyIdsLut, SectionId},
7 lookup,
8 parse::section,
9 File,
10};
11
12impl<'event> File<'event> {
14 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 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 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 ExactSizeIterator<Item = SectionId> + DoubleEndedIterator + 'a, lookup::existing::Error> {
122 let section_name = section::Name::from_str_unchecked(section_name);
123 let section_ids = self
124 .section_lookup_tree
125 .get(§ion_name)
126 .ok_or(lookup::existing::Error::SectionMissing)?;
127 let mut maybe_ids = None;
128 if let Some(subsection_name) = subsection_name {
129 for node in section_ids {
130 if let SectionBodyIdsLut::NonTerminal(subsection_lookup) = node {
131 maybe_ids = subsection_lookup.get(subsection_name).map(|v| v.iter().copied());
132 break;
133 }
134 }
135 } else {
136 for node in section_ids {
137 if let SectionBodyIdsLut::Terminal(subsection_lookup) = node {
138 maybe_ids = Some(subsection_lookup.iter().copied());
139 break;
140 }
141 }
142 }
143 maybe_ids.ok_or(lookup::existing::Error::SubSectionMissing)
144 }
145
146 pub(crate) fn section_ids_by_name<'a>(
147 &'a self,
148 section_name: &'a str,
149 ) -> Result<impl Iterator<Item = SectionId> + 'a, lookup::existing::Error> {
150 let section_name = section::Name::from_str_unchecked(section_name);
151 match self.section_lookup_tree.get(§ion_name) {
152 Some(lookup) => {
153 let mut lut = Vec::with_capacity(self.section_order.len());
154 for node in lookup {
155 match node {
156 SectionBodyIdsLut::Terminal(v) => lut.extend(v.iter().copied()),
157 SectionBodyIdsLut::NonTerminal(v) => lut.extend(v.values().flatten().copied()),
158 }
159 }
160
161 Ok(self.section_order.iter().filter(move |a| lut.contains(a)).copied())
162 }
163 None => Err(lookup::existing::Error::SectionMissing),
164 }
165 }
166}
167
168fn find_insert_pos_by_order(
169 sections_with_name: &[SectionId],
170 before_order: usize,
171 lookup_section_order: impl Fn(SectionId) -> usize,
172) -> usize {
173 let mut insert_pos = sections_with_name.len(); for (idx, candidate_id) in sections_with_name.iter().enumerate() {
175 let candidate_order = lookup_section_order(*candidate_id);
176 match candidate_order.cmp(&before_order) {
177 Ordering::Less => {}
178 Ordering::Equal => {
179 insert_pos = idx + 1; break;
181 }
182 Ordering::Greater => {
183 insert_pos = idx; break;
185 }
186 }
187 }
188 insert_pos
189}