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