1use std::{
2 borrow::Cow,
3 ops::{Deref, Range},
4};
5
6use bstr::{BStr, BString, ByteSlice, ByteVec};
7use smallvec::SmallVec;
8
9use crate::{
10 file::{
11 self,
12 mutable::{escape_value, Whitespace},
13 Index, Section, Size,
14 },
15 lookup, parse,
16 parse::{section::ValueName, Event},
17 value::{normalize, normalize_bstr, normalize_bstring},
18};
19
20#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
22pub struct SectionMut<'a, 'event> {
23 section: &'a mut Section<'event>,
24 implicit_newline: bool,
25 whitespace: Whitespace<'event>,
26 newline: SmallVec<[u8; 2]>,
27}
28
29impl<'event> SectionMut<'_, 'event> {
31 pub fn push<'b>(&mut self, value_name: ValueName<'event>, value: Option<&'b BStr>) -> &mut Self {
34 self.push_with_comment_inner(value_name, value, None);
35 self
36 }
37
38 pub fn push_with_comment<'b, 'c>(
43 &mut self,
44 value_name: ValueName<'event>,
45 value: Option<&'b BStr>,
46 comment: impl Into<&'c BStr>,
47 ) -> &mut Self {
48 self.push_with_comment_inner(value_name, value, comment.into().into());
49 self
50 }
51
52 fn push_with_comment_inner(&mut self, value_name: ValueName<'event>, value: Option<&BStr>, comment: Option<&BStr>) {
53 let body = &mut self.section.body.0;
54 if let Some(ws) = &self.whitespace.pre_key {
55 body.push(Event::Whitespace(ws.clone()));
56 }
57
58 body.push(Event::SectionValueName(value_name));
59 match value {
60 Some(value) => {
61 body.extend(self.whitespace.key_value_separators());
62 body.push(Event::Value(escape_value(value).into()));
63 }
64 None => body.push(Event::Value(Cow::Borrowed("".into()))),
65 }
66 if let Some(comment) = comment {
67 body.push(Event::Whitespace(Cow::Borrowed(" ".into())));
68 body.push(Event::Comment(parse::Comment {
69 tag: b'#',
70 text: Cow::Owned({
71 let mut c = Vec::with_capacity(comment.len());
72 let mut bytes = comment.iter().peekable();
73 if !bytes.peek().map_or(true, |b| b.is_ascii_whitespace()) {
74 c.insert(0, b' ');
75 }
76 c.extend(bytes.map(|b| if *b == b'\n' { b' ' } else { *b }));
77 c.into()
78 }),
79 }));
80 }
81 if self.implicit_newline {
82 body.push(Event::Newline(BString::from(self.newline.to_vec()).into()));
83 }
84 }
85
86 pub fn pop(&mut self) -> Option<(ValueName<'_>, Cow<'event, BStr>)> {
89 let mut values = Vec::new();
90 let body = &mut self.section.body.0;
92 while let Some(e) = body.pop() {
93 match e {
94 Event::SectionValueName(k) => {
95 if let Some(Event::Whitespace(_)) = body.last() {
97 body.pop();
98 }
99
100 if values.len() == 1 {
101 let value = values.pop().expect("vec is non-empty but popped to empty value");
102 return Some((k, normalize(value)));
103 }
104
105 return Some((
106 k,
107 normalize_bstring({
108 let mut s = BString::default();
109 for value in values.into_iter().rev() {
110 s.push_str(value.as_ref());
111 }
112 s
113 }),
114 ));
115 }
116 Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => values.push(v),
117 _ => (),
118 }
119 }
120 None
121 }
122
123 pub fn set(&mut self, value_name: ValueName<'event>, value: &BStr) -> Option<Cow<'event, BStr>> {
127 match self.key_and_value_range_by(&value_name) {
128 None => {
129 self.push(value_name, Some(value));
130 None
131 }
132 Some((key_range, value_range)) => {
133 let value_range = value_range.unwrap_or(key_range.end - 1..key_range.end);
134 let range_start = value_range.start;
135 let ret = self.remove_internal(value_range, false);
136 self.section
137 .body
138 .0
139 .insert(range_start, Event::Value(escape_value(value).into()));
140 Some(ret)
141 }
142 }
143 }
144
145 pub fn remove(&mut self, value_name: &str) -> Option<Cow<'event, BStr>> {
147 let key = ValueName::from_str_unchecked(value_name);
148 let (key_range, _value_range) = self.key_and_value_range_by(&key)?;
149 Some(self.remove_internal(key_range, true))
150 }
151
152 pub fn push_newline(&mut self) -> &mut Self {
155 self.section
156 .body
157 .0
158 .push(Event::Newline(Cow::Owned(BString::from(self.newline.to_vec()))));
159 self
160 }
161
162 pub fn newline(&self) -> &BStr {
164 self.newline.as_slice().as_bstr()
165 }
166
167 pub fn set_implicit_newline(&mut self, on: bool) -> &mut Self {
170 self.implicit_newline = on;
171 self
172 }
173
174 pub fn set_leading_whitespace(&mut self, whitespace: Option<Cow<'event, BStr>>) -> &mut Self {
185 assert!(
186 whitespace
187 .as_deref()
188 .map_or(true, |ws| ws.iter().all(u8::is_ascii_whitespace)),
189 "input whitespace must only contain whitespace characters."
190 );
191 self.whitespace.pre_key = whitespace;
192 self
193 }
194
195 #[must_use]
198 pub fn leading_whitespace(&self) -> Option<&BStr> {
199 self.whitespace.pre_key.as_deref()
200 }
201
202 #[must_use]
208 pub fn separator_whitespace(&self) -> (Option<&BStr>, Option<&BStr>) {
209 (self.whitespace.pre_sep.as_deref(), self.whitespace.post_sep.as_deref())
210 }
211}
212
213impl<'a, 'event> SectionMut<'a, 'event> {
215 pub(crate) fn new(section: &'a mut Section<'event>, newline: SmallVec<[u8; 2]>) -> Self {
216 let whitespace = Whitespace::from_body(§ion.body);
217 Self {
218 section,
219 implicit_newline: true,
220 whitespace,
221 newline,
222 }
223 }
224
225 pub(crate) fn get(
226 &self,
227 key: &ValueName<'_>,
228 start: Index,
229 end: Index,
230 ) -> Result<Cow<'_, BStr>, lookup::existing::Error> {
231 let mut expect_value = false;
232 let mut concatenated_value = BString::default();
233
234 for event in &self.section.0[start.0..end.0] {
235 match event {
236 Event::SectionValueName(event_key) if event_key == key => expect_value = true,
237 Event::Value(v) if expect_value => return Ok(normalize_bstr(v.as_ref())),
238 Event::ValueNotDone(v) if expect_value => {
239 concatenated_value.push_str(v.as_ref());
240 }
241 Event::ValueDone(v) if expect_value => {
242 concatenated_value.push_str(v.as_ref());
243 return Ok(normalize_bstring(concatenated_value));
244 }
245 _ => (),
246 }
247 }
248
249 Err(lookup::existing::Error::KeyMissing)
250 }
251
252 pub(crate) fn delete(&mut self, start: Index, end: Index) {
253 self.section.body.0.drain(start.0..end.0);
254 }
255
256 pub(crate) fn set_internal(&mut self, index: Index, key: ValueName<'event>, value: &BStr) -> Size {
257 let mut size = 0;
258
259 let body = &mut self.section.body.0;
260 body.insert(index.0, Event::Value(escape_value(value).into()));
261 size += 1;
262
263 let sep_events = self.whitespace.key_value_separators();
264 size += sep_events.len();
265 body.splice(index.0..index.0, sep_events.into_iter().rev())
266 .for_each(|_| {});
267
268 body.insert(index.0, Event::SectionValueName(key));
269 size += 1;
270
271 Size(size)
272 }
273
274 fn remove_internal(&mut self, range: Range<usize>, fix_whitespace: bool) -> Cow<'event, BStr> {
276 let events = &mut self.section.body.0;
277 if fix_whitespace && events.get(range.end).is_some_and(|ev| matches!(ev, Event::Newline(_))) {
278 events.remove(range.end);
279 }
280 let value = events
281 .drain(range.clone())
282 .fold(Cow::Owned(BString::default()), |mut acc: Cow<'_, BStr>, e| {
283 if let Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) = e {
284 acc.to_mut().extend(&**v);
285 }
286 acc
287 });
288 if fix_whitespace
289 && range
290 .start
291 .checked_sub(1)
292 .and_then(|pos| events.get(pos))
293 .is_some_and(|ev| matches!(ev, Event::Whitespace(_)))
294 {
295 events.remove(range.start - 1);
296 }
297 value
298 }
299}
300
301impl<'event> Deref for SectionMut<'_, 'event> {
302 type Target = file::Section<'event>;
303
304 fn deref(&self) -> &Self::Target {
305 self.section
306 }
307}
308
309impl<'event> file::section::Body<'event> {
310 pub(crate) fn as_mut(&mut self) -> &mut Vec<Event<'event>> {
311 &mut self.0
312 }
313}