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(§ion_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(§ion_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(§ion_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(§ion_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(§ion_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}