gix_config/file/access/raw.rs
1use std::collections::HashMap;
2
3use bstr::{BStr, BString};
4use smallvec::ToSmallVec;
5
6use crate::{
7 AsBStrOpt, AsKey, File,
8 file::{self, Index, Metadata, MultiValueMut, Size, ValueMut, mutable::multi_value::EntryData},
9 lookup,
10 parse::{Event, section},
11};
12
13/// # Raw value API
14///
15/// These functions are the raw value API, returning normalized byte strings.
16impl File {
17 /// Returns an uninterpreted value given a `key`.
18 ///
19 /// Consider [`Self::raw_values()`] if you want to get all values of
20 /// a multivar instead.
21 pub fn raw_value(&self, key: impl AsKey) -> Result<BString, lookup::existing::Error> {
22 let key = key.as_key();
23 self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, |_| true)
24 }
25
26 /// Returns an uninterpreted value given a section, an optional subsection
27 /// and value name.
28 ///
29 /// Consider [`Self::raw_values()`] if you want to get all values of
30 /// a multivar instead.
31 pub fn raw_value_by(
32 &self,
33 section_name: impl AsRef<str>,
34 subsection_name: impl AsBStrOpt,
35 value_name: impl AsRef<str>,
36 ) -> Result<BString, lookup::existing::Error> {
37 self.raw_value_filter_by(section_name, subsection_name, value_name, |_| true)
38 }
39
40 /// Returns an uninterpreted value and the section containing it given a `key`.
41 ///
42 /// Resolution is identical to [`raw_value()`][Self::raw_value()]: the last explicit value wins, even across
43 /// multiple matching sections.
44 pub fn raw_value_with_section(
45 &self,
46 key: impl AsKey,
47 ) -> Result<(BString, file::SectionRef<'_>), lookup::existing::Error> {
48 let key = key.as_key();
49 self.raw_value_with_section_by(key.section_name, key.subsection_name, key.value_name)
50 }
51
52 /// Returns an uninterpreted value and the section containing it given its individual key components.
53 ///
54 /// Resolution is identical to [`raw_value_by()`][Self::raw_value_by()]: the last explicit value wins, even
55 /// across multiple matching sections.
56 pub fn raw_value_with_section_by(
57 &self,
58 section_name: impl AsRef<str>,
59 subsection_name: impl AsBStrOpt,
60 value_name: impl AsRef<str>,
61 ) -> Result<(BString, file::SectionRef<'_>), lookup::existing::Error> {
62 self.raw_value_with_section_filter_by(section_name, subsection_name, value_name, |_| true)
63 }
64
65 /// Returns an uninterpreted value and the section containing it given a `key`, if the section passes `filter`.
66 ///
67 /// Resolution is identical to [`raw_value_filter()`][Self::raw_value_filter()]: the last explicit value in a
68 /// matching section wins.
69 pub fn raw_value_with_section_filter(
70 &self,
71 key: impl AsKey,
72 filter: impl FnMut(&Metadata) -> bool,
73 ) -> Result<(BString, file::SectionRef<'_>), lookup::existing::Error> {
74 let key = key.as_key();
75 self.raw_value_with_section_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
76 }
77
78 /// Returns an uninterpreted value and the section containing it given its individual key components, if the
79 /// section passes `filter`.
80 pub fn raw_value_with_section_filter_by(
81 &self,
82 section_name: impl AsRef<str>,
83 subsection_name: impl AsBStrOpt,
84 value_name: impl AsRef<str>,
85 filter: impl FnMut(&Metadata) -> bool,
86 ) -> Result<(BString, file::SectionRef<'_>), lookup::existing::Error> {
87 self.raw_value_with_section_filter_inner(
88 section_name.as_ref(),
89 subsection_name.as_bstr_opt(),
90 value_name.as_ref(),
91 filter,
92 )
93 }
94
95 /// Returns an uninterpreted value given a `key`, if it passes the `filter`.
96 ///
97 /// Consider [`Self::raw_values()`] if you want to get all values of
98 /// a multivar instead.
99 pub fn raw_value_filter(
100 &self,
101 key: impl AsKey,
102 filter: impl FnMut(&Metadata) -> bool,
103 ) -> Result<BString, lookup::existing::Error> {
104 let key = key.as_key();
105 self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
106 }
107
108 /// Returns an uninterpreted value given a section, an optional subsection
109 /// and value name, if it passes the `filter`.
110 ///
111 /// Consider [`Self::raw_values()`] if you want to get all values of
112 /// a multivar instead.
113 pub fn raw_value_filter_by(
114 &self,
115 section_name: impl AsRef<str>,
116 subsection_name: impl AsBStrOpt,
117 value_name: impl AsRef<str>,
118 filter: impl FnMut(&Metadata) -> bool,
119 ) -> Result<BString, lookup::existing::Error> {
120 self.raw_value_filter_inner(
121 section_name.as_ref(),
122 subsection_name.as_bstr_opt(),
123 value_name.as_ref(),
124 filter,
125 )
126 }
127
128 fn raw_value_filter_inner(
129 &self,
130 section_name: &str,
131 subsection_name: Option<&BStr>,
132 value_name: &str,
133 filter: impl FnMut(&Metadata) -> bool,
134 ) -> Result<BString, lookup::existing::Error> {
135 self.raw_value_with_section_filter_inner(section_name, subsection_name, value_name, filter)
136 .map(|(value, _section)| value)
137 }
138
139 fn raw_value_with_section_filter_inner(
140 &self,
141 section_name: &str,
142 subsection_name: Option<&BStr>,
143 value_name: &str,
144 mut filter: impl FnMut(&Metadata) -> bool,
145 ) -> Result<(BString, file::SectionRef<'_>), lookup::existing::Error> {
146 let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
147 for section_id in section_ids.rev() {
148 let section = self.sections.get(§ion_id).expect("known section id");
149 if !filter(section.meta()) {
150 continue;
151 }
152 if let Some(v) = section.body.value_implicit_in(&self.backing, value_name).flatten() {
153 return Ok((v, file::SectionRef::from_data(section, &self.backing)));
154 }
155 }
156
157 Err(lookup::existing::Error::KeyMissing)
158 }
159
160 /// Returns a mutable reference to an uninterpreted value given a `key`.
161 ///
162 /// Consider [`Self::raw_values_mut`] if you want to get mutable
163 /// references to all values of a multivar instead.
164 pub fn raw_value_mut(&mut self, key: impl AsKey) -> Result<ValueMut<'_>, lookup::existing::Error> {
165 let key = key.as_key();
166 self.raw_value_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, |_| true)
167 }
168
169 /// Returns a mutable reference to an uninterpreted value given a section,
170 /// an optional subsection and value name.
171 ///
172 /// Consider [`Self::raw_values_mut_by`] if you want to get mutable
173 /// references to all values of a multivar instead.
174 pub fn raw_value_mut_by(
175 &mut self,
176 section_name: impl AsRef<str>,
177 subsection_name: impl AsBStrOpt,
178 value_name: impl AsRef<str>,
179 ) -> Result<ValueMut<'_>, lookup::existing::Error> {
180 self.raw_value_mut_filter_by(section_name, subsection_name, value_name, |_| true)
181 }
182
183 /// Returns a mutable reference to an uninterpreted value given a `key`, if its section passes `filter`.
184 ///
185 /// Consider [`Self::raw_values_mut_by`] if you want to get mutable
186 /// references to all values of a multivar instead.
187 pub fn raw_value_mut_filter(
188 &mut self,
189 key: impl AsKey,
190 filter: impl FnMut(&Metadata) -> bool,
191 ) -> Result<ValueMut<'_>, lookup::existing::Error> {
192 let key = key.as_key();
193 self.raw_value_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, filter)
194 }
195
196 /// Returns a mutable reference to an uninterpreted value given a section, an optional subsection and value name,
197 /// if its section passes `filter`.
198 ///
199 /// Consider [`Self::raw_values_mut_by`] if you want to get mutable references to all values of a multivar instead.
200 pub fn raw_value_mut_filter_by(
201 &mut self,
202 section_name: impl AsRef<str>,
203 subsection_name: impl AsBStrOpt,
204 value_name: impl AsRef<str>,
205 filter: impl FnMut(&Metadata) -> bool,
206 ) -> Result<ValueMut<'_>, lookup::existing::Error> {
207 self.raw_value_mut_filter_inner(
208 section_name.as_ref(),
209 subsection_name.as_bstr_opt(),
210 value_name.as_ref(),
211 filter,
212 )
213 }
214
215 fn raw_value_mut_filter_inner(
216 &mut self,
217 section_name: &str,
218 subsection_name: Option<&BStr>,
219 value_name: &str,
220 mut filter: impl FnMut(&Metadata) -> bool,
221 ) -> Result<ValueMut<'_>, lookup::existing::Error> {
222 let mut section_ids = self
223 .section_ids_by_name_and_subname(section_name, subsection_name)?
224 .rev();
225 let key = section::ValueName::try_from(value_name)?;
226
227 while let Some(section_id) = section_ids.next() {
228 let mut index = 0;
229 let mut size = 0;
230 let mut found_key = false;
231 let section = self.sections.get(§ion_id).expect("known section id");
232 if !filter(section.meta()) {
233 continue;
234 }
235 for (i, event) in section.as_ref().iter().enumerate() {
236 match event {
237 Event::SectionValueName(event_key)
238 if event_key
239 .as_bstr_in(&self.backing)
240 .eq_ignore_ascii_case(key.0.as_slice()) =>
241 {
242 found_key = true;
243 index = i;
244 size = 1;
245 }
246 Event::Newline(_) | Event::Whitespace(_) | Event::ValueNotDone(_) if found_key => {
247 size += 1;
248 }
249 Event::ValueDone(_) | Event::Value(_) if found_key => {
250 found_key = false;
251 size += 1;
252 }
253 Event::KeyValueSeparator if found_key => {
254 size += 1;
255 }
256 _ => {}
257 }
258 }
259
260 if size == 0 {
261 continue;
262 }
263
264 drop(section_ids);
265 let nl = self.detect_newline_style().to_smallvec();
266 return Ok(ValueMut {
267 section: self.section_mut_from_id(section_id, nl).expect("known section-id"),
268 key,
269 index: Index(index),
270 size: Size(size),
271 });
272 }
273
274 Err(lookup::existing::Error::KeyMissing)
275 }
276
277 /// Returns all uninterpreted values given a `key`.
278 ///
279 /// The ordering means that the last of the returned values is the one that would be the
280 /// value used in the single-value case.
281 ///
282 /// # Examples
283 ///
284 /// If you have the following config:
285 ///
286 /// ```text
287 /// [core]
288 /// a = b
289 /// [core]
290 /// a = c
291 /// a = d
292 /// ```
293 ///
294 /// Attempting to get all values of `a` yields the following:
295 ///
296 /// ```
297 /// # use gix_config::File;
298 /// # use std::convert::TryFrom;
299 /// # let git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
300 /// assert_eq!(
301 /// git_config.raw_values("core.a").unwrap(),
302 /// vec![
303 /// bstr::BString::from("b"),
304 /// bstr::BString::from("c"),
305 /// bstr::BString::from("d"),
306 /// ],
307 /// );
308 /// ```
309 ///
310 /// Consider [`Self::raw_value`] if you want to get the resolved single
311 /// value for a given key, if your value does not support multi-valued values.
312 pub fn raw_values(&self, key: impl AsKey) -> Result<Vec<BString>, lookup::existing::Error> {
313 let key = key.as_key();
314 self.raw_values_by(key.section_name, key.subsection_name, key.value_name)
315 }
316
317 /// Returns all uninterpreted values given a section, an optional subsection
318 /// and value name in order of occurrence.
319 ///
320 /// The ordering means that the last of the returned values is the one that would be the
321 /// value used in the single-value case.
322 ///
323 /// # Examples
324 ///
325 /// If you have the following config:
326 ///
327 /// ```text
328 /// [core]
329 /// a = b
330 /// [core]
331 /// a = c
332 /// a = d
333 /// ```
334 ///
335 /// Attempting to get all values of `a` yields the following:
336 ///
337 /// ```
338 /// # use gix_config::File;
339 /// # use std::convert::TryFrom;
340 /// # let git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
341 /// assert_eq!(
342 /// git_config.raw_values_by("core", None, "a").unwrap(),
343 /// vec![
344 /// bstr::BString::from("b"),
345 /// bstr::BString::from("c"),
346 /// bstr::BString::from("d"),
347 /// ],
348 /// );
349 /// ```
350 ///
351 /// Consider [`Self::raw_value`] if you want to get the resolved single
352 /// value for a given value name, if your value does not support multi-valued values.
353 pub fn raw_values_by(
354 &self,
355 section_name: impl AsRef<str>,
356 subsection_name: impl AsBStrOpt,
357 value_name: impl AsRef<str>,
358 ) -> Result<Vec<BString>, lookup::existing::Error> {
359 self.raw_values_filter_by(section_name, subsection_name, value_name, |_| true)
360 }
361
362 /// Returns all uninterpreted values and their containing sections given a `key`, in order of occurrence.
363 pub fn raw_values_with_sections(
364 &self,
365 key: impl AsKey,
366 ) -> Result<Vec<(BString, file::SectionRef<'_>)>, lookup::existing::Error> {
367 let key = key.as_key();
368 self.raw_values_with_sections_by(key.section_name, key.subsection_name, key.value_name)
369 }
370
371 /// Returns all uninterpreted values and their containing sections given individual key components, in order of
372 /// occurrence.
373 pub fn raw_values_with_sections_by(
374 &self,
375 section_name: impl AsRef<str>,
376 subsection_name: impl AsBStrOpt,
377 value_name: impl AsRef<str>,
378 ) -> Result<Vec<(BString, file::SectionRef<'_>)>, lookup::existing::Error> {
379 self.raw_values_with_sections_filter_by(section_name, subsection_name, value_name, |_| true)
380 }
381
382 /// Returns all uninterpreted values and their containing sections given a `key`, if their sections pass `filter`,
383 /// in order of occurrence.
384 pub fn raw_values_with_sections_filter(
385 &self,
386 key: impl AsKey,
387 filter: impl FnMut(&Metadata) -> bool,
388 ) -> Result<Vec<(BString, file::SectionRef<'_>)>, lookup::existing::Error> {
389 let key = key.as_key();
390 self.raw_values_with_sections_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
391 }
392
393 /// Returns all uninterpreted values and their containing sections given individual key components, if their
394 /// sections pass `filter`, in order of occurrence.
395 pub fn raw_values_with_sections_filter_by(
396 &self,
397 section_name: impl AsRef<str>,
398 subsection_name: impl AsBStrOpt,
399 value_name: impl AsRef<str>,
400 filter: impl FnMut(&Metadata) -> bool,
401 ) -> Result<Vec<(BString, file::SectionRef<'_>)>, lookup::existing::Error> {
402 self.raw_values_with_sections_filter_inner(
403 section_name.as_ref(),
404 subsection_name.as_bstr_opt(),
405 value_name.as_ref(),
406 filter,
407 )
408 }
409
410 /// Returns all uninterpreted values given a `key`, if the value passes `filter`, in order of occurrence.
411 ///
412 /// The ordering means that the last of the returned values is the one that would be the
413 /// value used in the single-value case.
414 pub fn raw_values_filter(
415 &self,
416 key: impl AsKey,
417 filter: impl FnMut(&Metadata) -> bool,
418 ) -> Result<Vec<BString>, lookup::existing::Error> {
419 let key = key.as_key();
420 self.raw_values_filter_by(key.section_name, key.subsection_name, key.value_name, filter)
421 }
422
423 /// Returns all uninterpreted values given a section, an optional subsection
424 /// and value name, if the value passes `filter`, in order of occurrence.
425 ///
426 /// The ordering means that the last of the returned values is the one that would be the
427 /// value used in the single-value case.
428 pub fn raw_values_filter_by(
429 &self,
430 section_name: impl AsRef<str>,
431 subsection_name: impl AsBStrOpt,
432 value_name: impl AsRef<str>,
433 filter: impl FnMut(&Metadata) -> bool,
434 ) -> Result<Vec<BString>, lookup::existing::Error> {
435 self.raw_values_filter_inner(
436 section_name.as_ref(),
437 subsection_name.as_bstr_opt(),
438 value_name.as_ref(),
439 filter,
440 )
441 }
442
443 fn raw_values_filter_inner(
444 &self,
445 section_name: &str,
446 subsection_name: Option<&BStr>,
447 value_name: &str,
448 filter: impl FnMut(&Metadata) -> bool,
449 ) -> Result<Vec<BString>, lookup::existing::Error> {
450 self.raw_values_with_sections_filter_inner(section_name, subsection_name, value_name, filter)
451 .map(|values| values.into_iter().map(|(value, _section)| value).collect())
452 }
453
454 fn raw_values_with_sections_filter_inner(
455 &self,
456 section_name: &str,
457 subsection_name: Option<&BStr>,
458 value_name: &str,
459 mut filter: impl FnMut(&Metadata) -> bool,
460 ) -> Result<Vec<(BString, file::SectionRef<'_>)>, lookup::existing::Error> {
461 let mut values = Vec::new();
462 let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
463 for section_id in section_ids {
464 let section = self.sections.get(§ion_id).expect("known section id");
465 if !filter(section.meta()) {
466 continue;
467 }
468 let section_ref = file::SectionRef::from_data(section, &self.backing);
469 values.extend(
470 section
471 .body
472 .values_in(&self.backing, value_name)
473 .into_iter()
474 .map(|value| (value, section_ref)),
475 );
476 }
477
478 if values.is_empty() {
479 Err(lookup::existing::Error::KeyMissing)
480 } else {
481 Ok(values)
482 }
483 }
484
485 /// Returns mutable references to all uninterpreted values given a `key`.
486 ///
487 /// # Examples
488 ///
489 /// If you have the following config:
490 ///
491 /// ```text
492 /// [core]
493 /// a = b
494 /// [core]
495 /// a = c
496 /// a = d
497 /// ```
498 ///
499 /// Attempting to get all values of `a` yields the following:
500 ///
501 /// ```
502 /// # use gix_config::File;
503 /// # use std::convert::TryFrom;
504 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
505 /// assert_eq!(
506 /// git_config.raw_values("core.a")?,
507 /// vec![
508 /// bstr::BString::from("b"),
509 /// bstr::BString::from("c"),
510 /// bstr::BString::from("d")
511 /// ]
512 /// );
513 ///
514 /// git_config.raw_values_mut("core.a")?.set_all("g");
515 ///
516 /// assert_eq!(
517 /// git_config.raw_values("core.a")?,
518 /// vec![
519 /// bstr::BString::from("g"),
520 /// bstr::BString::from("g"),
521 /// bstr::BString::from("g")
522 /// ],
523 /// );
524 /// # Ok::<(), Box<dyn std::error::Error>>(())
525 /// ```
526 ///
527 /// Consider [`Self::raw_value`] if you want to get the resolved single
528 /// value for a given value name, if your value does not support multi-valued values.
529 ///
530 /// Note that this operation is relatively expensive, requiring a full
531 /// traversal of the config.
532 pub fn raw_values_mut(&mut self, key: impl AsKey) -> Result<MultiValueMut<'_>, lookup::existing::Error> {
533 let key = key.as_key();
534 self.raw_values_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, |_| true)
535 }
536
537 /// Returns mutable references to all uninterpreted values given a section,
538 /// an optional subsection and value name.
539 ///
540 /// # Examples
541 ///
542 /// If you have the following config:
543 ///
544 /// ```text
545 /// [core]
546 /// a = b
547 /// [core]
548 /// a = c
549 /// a = d
550 /// ```
551 ///
552 /// Attempting to get all values of `a` yields the following:
553 ///
554 /// ```
555 /// # use gix_config::File;
556 /// # use std::convert::TryFrom;
557 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
558 /// assert_eq!(
559 /// git_config.raw_values("core.a")?,
560 /// vec![
561 /// bstr::BString::from("b"),
562 /// bstr::BString::from("c"),
563 /// bstr::BString::from("d")
564 /// ]
565 /// );
566 ///
567 /// git_config.raw_values_mut_by("core", None, "a")?.set_all("g");
568 ///
569 /// assert_eq!(
570 /// git_config.raw_values("core.a")?,
571 /// vec![
572 /// bstr::BString::from("g"),
573 /// bstr::BString::from("g"),
574 /// bstr::BString::from("g")
575 /// ],
576 /// );
577 /// # Ok::<(), Box<dyn std::error::Error>>(())
578 /// ```
579 ///
580 /// Consider [`Self::raw_value`] if you want to get the resolved single
581 /// value for a given value name, if your value does not support multi-valued values.
582 ///
583 /// Note that this operation is relatively expensive, requiring a full
584 /// traversal of the config.
585 pub fn raw_values_mut_by(
586 &mut self,
587 section_name: impl AsRef<str>,
588 subsection_name: impl AsBStrOpt,
589 value_name: impl AsRef<str>,
590 ) -> Result<MultiValueMut<'_>, lookup::existing::Error> {
591 self.raw_values_mut_filter_by(section_name, subsection_name, value_name, |_| true)
592 }
593
594 /// Returns mutable references to all uninterpreted values given a `key`,
595 /// if their sections pass `filter`.
596 pub fn raw_values_mut_filter(
597 &mut self,
598 key: impl AsKey,
599 filter: impl FnMut(&Metadata) -> bool,
600 ) -> Result<MultiValueMut<'_>, lookup::existing::Error> {
601 let key = key.as_key();
602 self.raw_values_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, filter)
603 }
604
605 /// Returns mutable references to all uninterpreted values given a section,
606 /// an optional subsection and value name, if their sections pass `filter`.
607 pub fn raw_values_mut_filter_by(
608 &mut self,
609 section_name: impl AsRef<str>,
610 subsection_name: impl AsBStrOpt,
611 value_name: impl AsRef<str>,
612 filter: impl FnMut(&Metadata) -> bool,
613 ) -> Result<MultiValueMut<'_>, lookup::existing::Error> {
614 self.raw_values_mut_filter_inner(
615 section_name.as_ref(),
616 subsection_name.as_bstr_opt(),
617 value_name.as_ref(),
618 filter,
619 )
620 }
621
622 fn raw_values_mut_filter_inner(
623 &mut self,
624 section_name: &str,
625 subsection_name: Option<&BStr>,
626 value_name: &str,
627 mut filter: impl FnMut(&Metadata) -> bool,
628 ) -> Result<MultiValueMut<'_>, lookup::existing::Error> {
629 let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
630 let key = section::ValueName::try_from(value_name)?;
631
632 let mut offsets = HashMap::new();
633 let mut entries = Vec::new();
634 for section_id in section_ids.rev() {
635 let mut last_boundary = 0;
636 let mut expect_value = false;
637 let mut offset_list = Vec::new();
638 let mut offset_index = 0;
639 let section = self.sections.get(§ion_id).expect("known section-id");
640 if !filter(section.meta()) {
641 continue;
642 }
643 for (i, event) in section.as_ref().iter().enumerate() {
644 match event {
645 Event::SectionValueName(event_key)
646 if event_key
647 .as_bstr_in(&self.backing)
648 .eq_ignore_ascii_case(key.0.as_slice()) =>
649 {
650 expect_value = true;
651 offset_list.push(i - last_boundary);
652 offset_index += 1;
653 last_boundary = i;
654 }
655 Event::Value(_) | Event::ValueDone(_) if expect_value => {
656 expect_value = false;
657 entries.push(EntryData {
658 section_id,
659 offset_index,
660 });
661 offset_list.push(i - last_boundary + 1);
662 offset_index += 1;
663 last_boundary = i + 1;
664 }
665 _ => (),
666 }
667 }
668 offsets.insert(section_id, offset_list);
669 }
670
671 entries.sort();
672
673 if entries.is_empty() {
674 Err(lookup::existing::Error::KeyMissing)
675 } else {
676 Ok(MultiValueMut {
677 section: &mut self.sections,
678 backing: &mut self.backing,
679 key,
680 indices_and_sizes: entries,
681 offsets,
682 })
683 }
684 }
685
686 /// Sets a value in a given `key`.
687 /// Note that the parts leading to the value name must exist for this method to work, i.e. the
688 /// section and the subsection, if present.
689 ///
690 /// # Examples
691 ///
692 /// Given the config,
693 ///
694 /// ```text
695 /// [core]
696 /// a = b
697 /// [core]
698 /// a = c
699 /// a = d
700 /// ```
701 ///
702 /// Setting a new value to the key `core.a` will yield the following:
703 ///
704 /// ```
705 /// # use gix_config::File;
706 /// # use std::convert::TryFrom;
707 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
708 /// git_config.set_existing_raw_value("core.a", "e")?;
709 /// assert_eq!(git_config.raw_value("core.a")?, "e");
710 /// assert_eq!(
711 /// git_config.raw_values("core.a")?,
712 /// vec![
713 /// bstr::BString::from("b"),
714 /// bstr::BString::from("c"),
715 /// bstr::BString::from("e")
716 /// ],
717 /// );
718 /// # Ok::<(), Box<dyn std::error::Error>>(())
719 /// ```
720 pub fn set_existing_raw_value(
721 &mut self,
722 key: impl AsKey,
723 new_value: impl crate::AsBStr,
724 ) -> Result<(), crate::file::set_raw_value::Error> {
725 let key = key.as_key();
726 self.raw_value_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, |_| true)?
727 .set(new_value)?;
728 Ok(())
729 }
730
731 /// Sets a value in a given `section_name`, optional `subsection_name`, and `value_name`.
732 /// Note sections named `section_name` and `subsection_name` (if not `None`)
733 /// must exist for this method to work.
734 ///
735 /// # Examples
736 ///
737 /// Given the config,
738 ///
739 /// ```text
740 /// [core]
741 /// a = b
742 /// [core]
743 /// a = c
744 /// a = d
745 /// ```
746 ///
747 /// Setting a new value to the key `core.a` will yield the following:
748 ///
749 /// ```
750 /// # use gix_config::File;
751 /// # use std::convert::TryFrom;
752 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
753 /// git_config.set_existing_raw_value_by("core", None, "a", "e")?;
754 /// assert_eq!(git_config.raw_value("core.a")?, "e");
755 /// assert_eq!(
756 /// git_config.raw_values("core.a")?,
757 /// vec![
758 /// bstr::BString::from("b"),
759 /// bstr::BString::from("c"),
760 /// bstr::BString::from("e")
761 /// ],
762 /// );
763 /// # Ok::<(), Box<dyn std::error::Error>>(())
764 /// ```
765 pub fn set_existing_raw_value_by(
766 &mut self,
767 section_name: impl AsRef<str>,
768 subsection_name: impl AsBStrOpt,
769 value_name: impl AsRef<str>,
770 new_value: impl crate::AsBStr,
771 ) -> Result<(), crate::file::set_raw_value::Error> {
772 self.raw_value_mut_by(section_name, subsection_name, value_name)?
773 .set(new_value)?;
774 Ok(())
775 }
776
777 /// Sets a value in a given `key`.
778 /// Creates the section if necessary and the value as well, or overwrites the last existing value otherwise.
779 ///
780 /// # Examples
781 ///
782 /// Given the config,
783 ///
784 /// ```text
785 /// [core]
786 /// a = b
787 /// ```
788 ///
789 /// Setting a new value to the key `core.a` will yield the following:
790 ///
791 /// ```
792 /// # use gix_config::File;
793 /// # let mut git_config = gix_config::File::try_from("[core]a=b").unwrap();
794 /// let prev = git_config.set_raw_value(&"core.a", "e")?;
795 /// git_config.set_raw_value(&"core.b", "f")?;
796 /// assert_eq!(prev.expect("present"), "b");
797 /// assert_eq!(git_config.raw_value("core.a")?, "e");
798 /// assert_eq!(git_config.raw_value("core.b")?, "f");
799 /// # Ok::<(), Box<dyn std::error::Error>>(())
800 /// ```
801 pub fn set_raw_value(
802 &mut self,
803 key: impl AsKey,
804 new_value: impl crate::AsBStr,
805 ) -> Result<Option<BString>, crate::file::set_raw_value::Error> {
806 self.set_raw_value_filter(key, new_value, |_| true)
807 }
808
809 /// Sets a value in a given `section_name`, optional `subsection_name`, and `value_name`.
810 /// Creates the section if necessary and the value as well, or overwrites the last existing value otherwise.
811 ///
812 /// # Examples
813 ///
814 /// Given the config,
815 ///
816 /// ```text
817 /// [core]
818 /// a = b
819 /// ```
820 ///
821 /// Setting a new value to the key `core.a` will yield the following:
822 ///
823 /// ```
824 /// # use gix_config::File;
825 /// # let mut git_config = gix_config::File::try_from("[core]a=b").unwrap();
826 /// let prev = git_config.set_raw_value_by("core", None, "a", "e")?;
827 /// git_config.set_raw_value_by("core", None, "b", "f")?;
828 /// assert_eq!(prev.expect("present"), "b");
829 /// assert_eq!(git_config.raw_value("core.a")?, "e");
830 /// assert_eq!(git_config.raw_value("core.b")?, "f");
831 /// # Ok::<(), Box<dyn std::error::Error>>(())
832 /// ```
833 pub fn set_raw_value_by(
834 &mut self,
835 section_name: impl AsRef<str>,
836 subsection_name: impl AsBStrOpt,
837 value_name: impl AsRef<str>,
838 new_value: impl crate::AsBStr,
839 ) -> Result<Option<BString>, crate::file::set_raw_value::Error> {
840 self.set_raw_value_filter_by(section_name, subsection_name, value_name, new_value, |_| true)
841 }
842
843 /// Similar to [`set_raw_value()`](Self::set_raw_value()), but only sets existing values in sections matching
844 /// `filter`, creating a new section otherwise.
845 pub fn set_raw_value_filter(
846 &mut self,
847 key: impl AsKey,
848 new_value: impl crate::AsBStr,
849 filter: impl FnMut(&Metadata) -> bool,
850 ) -> Result<Option<BString>, crate::file::set_raw_value::Error> {
851 let key = key.as_key();
852 self.set_raw_value_filter_by_inner(key.section_name, key.subsection_name, key.value_name, new_value, filter)
853 }
854
855 /// Similar to [`set_raw_value_by()`](Self::set_raw_value_by()), but only sets existing values in sections matching
856 /// `filter`, creating a new section otherwise.
857 pub fn set_raw_value_filter_by(
858 &mut self,
859 section_name: impl AsRef<str>,
860 subsection_name: impl AsBStrOpt,
861 value_name: impl AsRef<str>,
862 new_value: impl crate::AsBStr,
863 filter: impl FnMut(&Metadata) -> bool,
864 ) -> Result<Option<BString>, crate::file::set_raw_value::Error> {
865 self.set_raw_value_filter_by_inner(
866 section_name.as_ref(),
867 subsection_name.as_bstr_opt(),
868 value_name.as_ref(),
869 new_value,
870 filter,
871 )
872 }
873
874 fn set_raw_value_filter_by_inner(
875 &mut self,
876 section_name: &str,
877 subsection_name: Option<&BStr>,
878 value_name: &str,
879 new_value: impl crate::AsBStr,
880 filter: impl FnMut(&Metadata) -> bool,
881 ) -> Result<Option<BString>, crate::file::set_raw_value::Error> {
882 let key = section::ValueName::try_from(value_name)?;
883 let mut section = self.section_mut_or_create_new_filter_inner(section_name, subsection_name, filter)?;
884 section.set_inner(key, new_value.as_bstr()).map_err(Into::into)
885 }
886
887 /// Sets a multivar in a given `key`.
888 ///
889 /// This internally zips together the new values and the existing values.
890 /// As a result, if more new values are provided than the current amount of
891 /// multivars, then the latter values are not applied. If there are less
892 /// new values than old ones then the remaining old values are unmodified.
893 ///
894 /// **Note**: Mutation order is _not_ guaranteed and is non-deterministic.
895 /// If you need finer control over which values of the multivar are set,
896 /// consider using [`raw_values_mut()`](Self::raw_values_mut()), which will let you iterate
897 /// and check over the values instead. This is best used as a convenience
898 /// function for setting multivars whose values should be treated as an
899 /// unordered set.
900 ///
901 /// # Examples
902 ///
903 /// Let us use the follow config for all examples:
904 ///
905 /// ```text
906 /// [core]
907 /// a = b
908 /// [core]
909 /// a = c
910 /// a = d
911 /// ```
912 ///
913 /// Setting an equal number of values:
914 ///
915 /// ```
916 /// # use gix_config::File;
917 /// # use std::convert::TryFrom;
918 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
919 /// let new_values = vec![
920 /// "x",
921 /// "y",
922 /// "z",
923 /// ];
924 /// git_config.set_existing_raw_multi_value("core.a", new_values.into_iter())?;
925 /// let fetched_config = git_config.raw_values("core.a")?;
926 /// assert!(fetched_config.iter().any(|v| v == "x"));
927 /// assert!(fetched_config.iter().any(|v| v == "y"));
928 /// assert!(fetched_config.iter().any(|v| v == "z"));
929 /// # Ok::<(), Box<dyn std::error::Error>>(())
930 /// ```
931 ///
932 /// Setting less than the number of present values sets the first ones found:
933 ///
934 /// ```
935 /// # use gix_config::File;
936 /// # use std::convert::TryFrom;
937 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
938 /// let new_values = vec![
939 /// "x",
940 /// "y",
941 /// ];
942 /// git_config.set_existing_raw_multi_value("core.a", new_values.into_iter())?;
943 /// let fetched_config = git_config.raw_values("core.a")?;
944 /// assert!(fetched_config.iter().any(|v| v == "x"));
945 /// assert!(fetched_config.iter().any(|v| v == "y"));
946 /// # Ok::<(), Box<dyn std::error::Error>>(())
947 /// ```
948 ///
949 /// Setting more than the number of present values discards the rest:
950 ///
951 /// ```
952 /// # use gix_config::File;
953 /// # use std::convert::TryFrom;
954 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
955 /// let new_values = vec![
956 /// "x",
957 /// "y",
958 /// "z",
959 /// "discarded",
960 /// ];
961 /// git_config.set_existing_raw_multi_value("core.a", new_values)?;
962 /// assert!(!git_config.raw_values("core.a")?.iter().any(|v| v == "discarded"));
963 /// # Ok::<(), Box<dyn std::error::Error>>(())
964 /// ```
965 pub fn set_existing_raw_multi_value<Iter, Item>(
966 &mut self,
967 key: impl AsKey,
968 new_values: Iter,
969 ) -> Result<(), crate::file::set_raw_value::Error>
970 where
971 Iter: IntoIterator<Item = Item>,
972 Item: crate::AsBStr,
973 {
974 let key = key.as_key();
975 self.raw_values_mut_filter_inner(key.section_name, key.subsection_name, key.value_name, |_| true)?
976 .set_values(new_values)?;
977 Ok(())
978 }
979
980 /// Sets a multivar in a given section, optional subsection, and key value.
981 ///
982 /// This internally zips together the new values and the existing values.
983 /// As a result, if more new values are provided than the current amount of
984 /// multivars, then the latter values are not applied. If there are less
985 /// new values than old ones then the remaining old values are unmodified.
986 ///
987 /// **Note**: Mutation order is _not_ guaranteed and is non-deterministic.
988 /// If you need finer control over which values of the multivar are set,
989 /// consider using [`raw_values_mut()`](Self::raw_values_mut()), which will let you iterate
990 /// and check over the values instead. This is best used as a convenience
991 /// function for setting multivars whose values should be treated as an
992 /// unordered set.
993 ///
994 /// # Examples
995 ///
996 /// Let us use the follow config for all examples:
997 ///
998 /// ```text
999 /// [core]
1000 /// a = b
1001 /// [core]
1002 /// a = c
1003 /// a = d
1004 /// ```
1005 ///
1006 /// Setting an equal number of values:
1007 ///
1008 /// ```
1009 /// # use gix_config::File;
1010 /// # use std::convert::TryFrom;
1011 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
1012 /// let new_values = vec![
1013 /// "x",
1014 /// "y",
1015 /// "z",
1016 /// ];
1017 /// git_config.set_existing_raw_multi_value_by("core", None, "a", new_values.into_iter())?;
1018 /// let fetched_config = git_config.raw_values("core.a")?;
1019 /// assert!(fetched_config.iter().any(|v| v == "x"));
1020 /// assert!(fetched_config.iter().any(|v| v == "y"));
1021 /// assert!(fetched_config.iter().any(|v| v == "z"));
1022 /// # Ok::<(), Box<dyn std::error::Error>>(())
1023 /// ```
1024 ///
1025 /// Setting less than the number of present values sets the first ones found:
1026 ///
1027 /// ```
1028 /// # use gix_config::File;
1029 /// # use std::convert::TryFrom;
1030 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
1031 /// let new_values = vec![
1032 /// "x",
1033 /// "y",
1034 /// ];
1035 /// git_config.set_existing_raw_multi_value_by("core", None, "a", new_values.into_iter())?;
1036 /// let fetched_config = git_config.raw_values("core.a")?;
1037 /// assert!(fetched_config.iter().any(|v| v == "x"));
1038 /// assert!(fetched_config.iter().any(|v| v == "y"));
1039 /// # Ok::<(), Box<dyn std::error::Error>>(())
1040 /// ```
1041 ///
1042 /// Setting more than the number of present values discards the rest:
1043 ///
1044 /// ```
1045 /// # use gix_config::File;
1046 /// # use std::convert::TryFrom;
1047 /// # let mut git_config = gix_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
1048 /// let new_values = vec![
1049 /// "x",
1050 /// "y",
1051 /// "z",
1052 /// "discarded",
1053 /// ];
1054 /// git_config.set_existing_raw_multi_value_by("core", None, "a", new_values)?;
1055 /// assert!(!git_config.raw_values("core.a")?.iter().any(|v| v == "discarded"));
1056 /// # Ok::<(), Box<dyn std::error::Error>>(())
1057 /// ```
1058 pub fn set_existing_raw_multi_value_by<Iter, Item>(
1059 &mut self,
1060 section_name: impl AsRef<str>,
1061 subsection_name: impl AsBStrOpt,
1062 value_name: impl AsRef<str>,
1063 new_values: Iter,
1064 ) -> Result<(), crate::file::set_raw_value::Error>
1065 where
1066 Iter: IntoIterator<Item = Item>,
1067 Item: crate::AsBStr,
1068 {
1069 self.raw_values_mut_by(section_name, subsection_name, value_name)?
1070 .set_values(new_values)?;
1071 Ok(())
1072 }
1073}