1use std::{collections::HashMap, ops::DerefMut};
2
3use bstr::{BStr, BString, ByteVec};
4
5use crate::{
6 file::{
7 self, SectionData, SectionId,
8 mutable::{Whitespace, escape_value},
9 },
10 lookup,
11 parse::{Event, section},
12 value::normalize,
13};
14
15#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
17pub(crate) struct EntryData {
18 pub(crate) section_id: SectionId,
19 pub(crate) offset_index: usize,
20}
21
22#[derive(Debug)]
24pub struct MultiValueMut<'borrow> {
25 pub(crate) section: &'borrow mut HashMap<SectionId, SectionData>,
26 pub(crate) backing: &'borrow mut Vec<u8>,
27 pub(crate) key: section::ValueName,
28 pub(crate) indices_and_sizes: Vec<EntryData>,
32 pub(crate) offsets: HashMap<SectionId, Vec<usize>>,
36}
37
38impl MultiValueMut<'_> {
39 pub fn get(&self) -> Result<Vec<BString>, 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)
54 if section_key
55 .as_bstr_in(self.backing)
56 .eq_ignore_ascii_case(self.key.0.as_slice()) =>
57 {
58 expect_value = true;
59 }
60 Event::Value(v) if expect_value => {
61 expect_value = false;
62 values.push(normalize(v.as_slice_in(self.backing)).into_owned());
63 }
64 Event::ValueNotDone(v) if expect_value => concatenated_value.push_str(v.as_slice_in(self.backing)),
65 Event::ValueDone(v) if expect_value => {
66 expect_value = false;
67 concatenated_value.push_str(v.as_slice_in(self.backing));
68 let concatenated_value = std::mem::take(&mut concatenated_value);
69 values.push(normalize(&concatenated_value).into_owned());
70 }
71 _ => (),
72 }
73 }
74 }
75
76 if values.is_empty() {
77 return Err(lookup::existing::Error::KeyMissing);
78 }
79
80 Ok(values)
81 }
82
83 #[must_use]
85 pub fn len(&self) -> usize {
86 self.indices_and_sizes.len()
87 }
88
89 #[must_use]
92 pub fn is_empty(&self) -> bool {
93 self.indices_and_sizes.is_empty()
94 }
95
96 pub fn set_string_at(&mut self, index: usize, value: impl AsRef<str>) -> Result<(), crate::parse::span::Error> {
102 self.set_at(index, value.as_ref())
103 }
104
105 pub fn set_at(&mut self, index: usize, value: impl crate::AsBStr) -> Result<(), crate::parse::span::Error> {
111 let EntryData {
112 section_id,
113 offset_index,
114 } = self.indices_and_sizes[index];
115 MultiValueMut::set_value_inner(
116 &self.key,
117 &mut self.offsets,
118 &mut self.section.get_mut(§ion_id).expect("known section id").body,
119 self.backing,
120 section_id,
121 offset_index,
122 value.as_bstr(),
123 )
124 }
125
126 pub fn set_values<Iter, Item>(&mut self, values: Iter) -> Result<(), crate::parse::span::Error>
134 where
135 Iter: IntoIterator<Item = Item>,
136 Item: crate::AsBStr,
137 {
138 for (
139 EntryData {
140 section_id,
141 offset_index,
142 },
143 value,
144 ) in self.indices_and_sizes.iter().zip(values)
145 {
146 Self::set_value_inner(
147 &self.key,
148 &mut self.offsets,
149 &mut self.section.get_mut(section_id).expect("known section id").body,
150 self.backing,
151 *section_id,
152 *offset_index,
153 value.as_bstr(),
154 )?;
155 }
156 Ok(())
157 }
158
159 pub fn set_all(&mut self, input: impl crate::AsBStr) -> Result<(), crate::parse::span::Error> {
162 let input = input.as_bstr();
163 for EntryData {
164 section_id,
165 offset_index,
166 } in &self.indices_and_sizes
167 {
168 Self::set_value_inner(
169 &self.key,
170 &mut self.offsets,
171 &mut self.section.get_mut(section_id).expect("known section id").body,
172 self.backing,
173 *section_id,
174 *offset_index,
175 input,
176 )?;
177 }
178 Ok(())
179 }
180
181 fn set_value_inner(
182 value_name: §ion::ValueName,
183 offsets: &mut HashMap<SectionId, Vec<usize>>,
184 section: &mut file::section::BodyData,
185 backing: &mut Vec<u8>,
186 section_id: SectionId,
187 offset_index: usize,
188 value: &BStr,
189 ) -> Result<(), crate::parse::span::Error> {
190 let (offset, size) = MultiValueMut::index_and_size(offsets, section_id, offset_index);
191 let whitespace = Whitespace::from_body(section, backing);
192 let value = crate::parse::Span::append(backing, &escape_value(value))?;
193 let key_sep_events = whitespace.key_value_separators(backing)?;
194 let key = crate::parse::Span::append(backing, value_name.0.as_slice())?;
195
196 let section = section.as_mut();
197 section.drain(offset..offset + size);
198 MultiValueMut::set_offset(offsets, section_id, offset_index, 2 + key_sep_events.len());
199 section.insert(offset, Event::Value(value));
200 section
201 .splice(offset..offset, key_sep_events.into_iter().rev())
202 .for_each(|_| {});
203 section.insert(offset, Event::SectionValueName(key));
204 Ok(())
205 }
206
207 pub fn delete(&mut self, index: usize) {
214 let EntryData {
215 section_id,
216 offset_index,
217 } = &self.indices_and_sizes[index];
218 let (offset, size) = MultiValueMut::index_and_size(&self.offsets, *section_id, *offset_index);
219 if size == 0 {
220 return;
221 }
222 self.section
223 .get_mut(section_id)
224 .expect("known section id")
225 .body
226 .as_mut()
227 .drain(offset..offset + size);
228
229 Self::set_offset(&mut self.offsets, *section_id, *offset_index, 0);
230 self.indices_and_sizes.remove(index);
231 }
232
233 pub fn delete_all(&mut self) {
236 for EntryData {
237 section_id,
238 offset_index,
239 } in &self.indices_and_sizes
240 {
241 let (offset, size) = MultiValueMut::index_and_size(&self.offsets, *section_id, *offset_index);
242 if size == 0 {
243 continue;
244 }
245 self.section
246 .get_mut(section_id)
247 .expect("known section id")
248 .body
249 .as_mut()
250 .drain(offset..offset + size);
251 Self::set_offset(&mut self.offsets, *section_id, *offset_index, 0);
252 }
253 self.indices_and_sizes.clear();
254 }
255
256 fn index_and_size(
257 offsets: &HashMap<SectionId, Vec<usize>>,
258 section_id: SectionId,
259 offset_index: usize,
260 ) -> (usize, usize) {
261 offsets
262 .get(§ion_id)
263 .expect("known section id")
264 .iter()
265 .take(offset_index + 1)
266 .fold((0, 0), |(total_ofs, ofs), size| (total_ofs + ofs, *size))
267 }
268
269 fn set_offset(
272 offsets: &mut HashMap<SectionId, Vec<usize>>,
273 section_id: SectionId,
274 offset_index: usize,
275 value: usize,
276 ) {
277 *offsets
278 .get_mut(§ion_id)
279 .expect("known section id")
280 .get_mut(offset_index)
281 .unwrap()
282 .deref_mut() = value;
283 }
284}