Skip to main content

gix_config/file/access/
raw.rs

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