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