Skip to main content

gix_config/file/access/
raw.rs

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