1 use std
::{cmp::Ordering, collections::HashMap}
;
6 file
::{self, SectionBodyIdsLut, SectionId}
,
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();
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
{
28 .entry(subsection_name
.clone())
30 .push(new_section_id
);
35 let mut map
= HashMap
::new();
36 map
.insert(subsection_name
, vec
![new_section_id
]);
37 lookup
.push(SectionBodyIdsLut
::NonTerminal(map
));
40 for node
in lookup
.iter_mut() {
41 if let SectionBodyIdsLut
::Terminal(vec
) = node
{
43 vec
.push(new_section_id
);
48 lookup
.push(SectionBodyIdsLut
::Terminal(vec
![new_section_id
]));
51 self.section_order
.push_back(new_section_id
);
52 self.section_id_counter
+= 1;
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
;
64 .find_map(|(idx
, id
)| (*id
== section_id
).then_some(idx
))
65 .expect("before-section exists")
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();
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
{
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
,
88 sections_with_name_and_subsection_name
.insert(insert_pos
, new_section_id
);
93 let mut map
= HashMap
::new();
94 map
.insert(subsection_name
, vec
![new_section_id
]);
95 lookup
.push(SectionBodyIdsLut
::NonTerminal(map
));
98 for node
in lookup
.iter_mut() {
99 if let SectionBodyIdsLut
::Terminal(sections_with_name
) = node
{
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
);
107 lookup
.push(SectionBodyIdsLut
::Terminal(vec
![new_section_id
]));
111 self.section_order
.insert(before_order
+ 1, new_section_id
);
112 self.section_id_counter
+= 1;
116 /// Returns the mapping between section and subsection name to section ids.
117 pub(crate) fn section_ids_by_name_and_subname
<'a
>(
119 section_name
: &'a
str,
120 subsection_name
: Option
<&BStr
>,
121 ) -> Result
<impl Iterator
<Item
= SectionId
> + ExactSizeIterator
+ DoubleEndedIterator
+ '_
, lookup
::existing
::Error
>
123 let section_name
= section
::Name
::from_str_unchecked(section_name
);
124 let section_ids
= self
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());
137 for node
in section_ids
{
138 if let SectionBodyIdsLut
::Terminal(subsection_lookup
) = node
{
139 maybe_ids
= Some(subsection_lookup
.iter().copied());
144 maybe_ids
.ok_or(lookup
::existing
::Error
::SubSectionMissing
)
147 pub(crate) fn section_ids_by_name
<'a
>(
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(§ion_name
) {
154 let mut lut
= Vec
::with_capacity(self.section_order
.len());
157 SectionBodyIdsLut
::Terminal(v
) => lut
.extend(v
.iter().copied()),
158 SectionBodyIdsLut
::NonTerminal(v
) => lut
.extend(v
.values().flatten().copied()),
162 Ok(self.section_order
.iter().filter(move |a
| lut
.contains(a
)).copied())
164 None
=> Err(lookup
::existing
::Error
::SectionMissing
),
169 fn find_insert_pos_by_order(
170 sections_with_name
: &[SectionId
],
172 lookup_section_order
: impl Fn(SectionId
) -> 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
) {
180 insert_pos
= idx
+ 1; // insert right after this one
183 Ordering
::Greater
=> {
184 insert_pos
= idx
; // insert before this one