1use std::{borrow::Cow, collections::HashMap, ops::DerefMut};
2
3use bstr::{BStr, BString, ByteVec};
4
5use crate::{
6 file::{
7 self,
8 mutable::{escape_value, Whitespace},
9 Section, SectionId,
10 },
11 lookup,
12 parse::{section, Event},
13 value::{normalize_bstr, normalize_bstring},
14};
15
16#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
18pub(crate) struct EntryData {
19 pub(crate) section_id: SectionId,
20 pub(crate) offset_index: usize,
21}
22
23#[derive(PartialEq, Eq, Debug)]
25pub struct MultiValueMut<'borrow, 'lookup, 'event> {
26 pub(crate) section: &'borrow mut HashMap<SectionId, Section<'event>>,
27 pub(crate) key: section::ValueName<'lookup>,
28 pub(crate) indices_and_sizes: Vec<EntryData>,
32 pub(crate) offsets: HashMap<SectionId, Vec<usize>>,
36}
37
38impl<'lookup, 'event> MultiValueMut<'_, 'lookup, 'event> {
39 pub fn get(&self) -> Result<Vec<Cow<'_, BStr>>, lookup::existing::Error> {
41 let mut expect_value = false;
42 let mut values = Vec::new();
43 let mut concatenated_value = BString::default();
44
45 for EntryData {
46 section_id,
47 offset_index,
48 } in &self.indices_and_sizes
49 {
50 let (offset, size) = MultiValueMut::index_and_size(&self.offsets, *section_id, *offset_index);
51 for event in &self.section.get(section_id).expect("known section id").as_ref()[offset..offset + size] {
52 match event {
53 Event::SectionValueName(section_key) if *section_key == self.key => expect_value = true,
54 Event::Value(v) if expect_value => {
55 expect_value = false;
56 values.push(normalize_bstr(v.as_ref()));
57 }
58 Event::ValueNotDone(v) if expect_value => concatenated_value.push_str(v.as_ref()),
59 Event::ValueDone(v) if expect_value => {
60 expect_value = false;
61 concatenated_value.push_str(v.as_ref());
62 values.push(normalize_bstring(std::mem::take(&mut concatenated_value)));
63 }
64 _ => (),
65 }
66 }
67 }
68
69 if values.is_empty() {
70 return Err(lookup::existing::Error::KeyMissing);
71 }
72
73 Ok(values)
74 }
75
76 #[must_use]
78 pub fn len(&self) -> usize {
79 self.indices_and_sizes.len()
80 }
81
82 #[must_use]
85 pub fn is_empty(&self) -> bool {
86 self.indices_and_sizes.is_empty()
87 }
88
89 pub fn set_string_at(&mut self, index: usize, value: impl AsRef<str>) {
95 self.set_at(index, value.as_ref());
96 }
97
98 pub fn set_at<'a>(&mut self, index: usize, value: impl Into<&'a BStr>) {
104 let EntryData {
105 section_id,
106 offset_index,
107 } = self.indices_and_sizes[index];
108 MultiValueMut::set_value_inner(
109 &self.key,
110 &mut self.offsets,
111 &mut self.section.get_mut(§ion_id).expect("known section id").body,
112 section_id,
113 offset_index,
114 value.into(),
115 );
116 }
117
118 pub fn set_values<'a, Iter, Item>(&mut self, values: Iter)
126 where
127 Iter: IntoIterator<Item = Item>,
128 Item: Into<&'a BStr>,
129 {
130 for (
131 EntryData {
132 section_id,
133 offset_index,
134 },
135 value,
136 ) in self.indices_and_sizes.iter().zip(values)
137 {
138 Self::set_value_inner(
139 &self.key,
140 &mut self.offsets,
141 &mut self.section.get_mut(section_id).expect("known section id").body,
142 *section_id,
143 *offset_index,
144 value.into(),
145 );
146 }
147 }
148
149 pub fn set_all<'a>(&mut self, input: impl Into<&'a BStr>) {
152 let input = input.into();
153 for EntryData {
154 section_id,
155 offset_index,
156 } in &self.indices_and_sizes
157 {
158 Self::set_value_inner(
159 &self.key,
160 &mut self.offsets,
161 &mut self.section.get_mut(section_id).expect("known section id").body,
162 *section_id,
163 *offset_index,
164 input,
165 );
166 }
167 }
168
169 fn set_value_inner<'a: 'event>(
170 value_name: §ion::ValueName<'lookup>,
171 offsets: &mut HashMap<SectionId, Vec<usize>>,
172 section: &mut file::section::Body<'event>,
173 section_id: SectionId,
174 offset_index: usize,
175 value: &BStr,
176 ) {
177 let (offset, size) = MultiValueMut::index_and_size(offsets, section_id, offset_index);
178 let whitespace = Whitespace::from_body(section);
179 let section = section.as_mut();
180 section.drain(offset..offset + size);
181
182 let key_sep_events = whitespace.key_value_separators();
183 MultiValueMut::set_offset(offsets, section_id, offset_index, 2 + key_sep_events.len());
184 section.insert(offset, Event::Value(escape_value(value).into()));
185 section
186 .splice(offset..offset, key_sep_events.into_iter().rev())
187 .for_each(|_| {});
188 section.insert(offset, Event::SectionValueName(value_name.to_owned()));
189 }
190
191 pub fn delete(&mut self, index: usize) {
198 let EntryData {
199 section_id,
200 offset_index,
201 } = &self.indices_and_sizes[index];
202 let (offset, size) = MultiValueMut::index_and_size(&self.offsets, *section_id, *offset_index);
203 if size == 0 {
204 return;
205 }
206 self.section
207 .get_mut(section_id)
208 .expect("known section id")
209 .body
210 .as_mut()
211 .drain(offset..offset + size);
212
213 Self::set_offset(&mut self.offsets, *section_id, *offset_index, 0);
214 self.indices_and_sizes.remove(index);
215 }
216
217 pub fn delete_all(&mut self) {
220 for EntryData {
221 section_id,
222 offset_index,
223 } in &self.indices_and_sizes
224 {
225 let (offset, size) = MultiValueMut::index_and_size(&self.offsets, *section_id, *offset_index);
226 if size == 0 {
227 continue;
228 }
229 self.section
230 .get_mut(section_id)
231 .expect("known section id")
232 .body
233 .as_mut()
234 .drain(offset..offset + size);
235 Self::set_offset(&mut self.offsets, *section_id, *offset_index, 0);
236 }
237 self.indices_and_sizes.clear();
238 }
239
240 fn index_and_size(
241 offsets: &'lookup HashMap<SectionId, Vec<usize>>,
242 section_id: SectionId,
243 offset_index: usize,
244 ) -> (usize, usize) {
245 offsets
246 .get(§ion_id)
247 .expect("known section id")
248 .iter()
249 .take(offset_index + 1)
250 .fold((0, 0), |(total_ofs, ofs), size| (total_ofs + ofs, *size))
251 }
252
253 fn set_offset(
256 offsets: &mut HashMap<SectionId, Vec<usize>>,
257 section_id: SectionId,
258 offset_index: usize,
259 value: usize,
260 ) {
261 *offsets
262 .get_mut(§ion_id)
263 .expect("known section id")
264 .get_mut(offset_index)
265 .unwrap()
266 .deref_mut() = value;
267 }
268}