Skip to main content

gix_config/file/
mod.rs

1//! A high level wrapper around a single or multiple `git-config` file, for reading and mutation.
2use std::{
3    collections::HashMap,
4    ops::{Add, AddAssign},
5    path::PathBuf,
6};
7
8use bstr::BString;
9use gix_features::threading::OwnShared;
10
11mod mutable;
12pub use mutable::{multi_value::MultiValueMut, section::SectionMut, value::ValueMut};
13
14///
15pub mod init;
16
17mod access;
18mod impls;
19///
20pub mod includes;
21mod meta;
22mod util;
23
24///
25pub mod section;
26
27///
28pub mod rename_section {
29    /// The error returned by [`File::rename_section(…)`][crate::File::rename_section()].
30    #[derive(Debug, thiserror::Error)]
31    #[expect(missing_docs)]
32    pub enum Error {
33        #[error(transparent)]
34        Lookup(#[from] crate::lookup::existing::Error),
35        #[error(transparent)]
36        Section(#[from] crate::parse::section::header::Error),
37    }
38}
39
40///
41pub mod set_raw_value {
42    /// The error returned by [`File::set_raw_value(…)`][crate::File::set_raw_value()].
43    #[derive(Debug, thiserror::Error)]
44    #[expect(missing_docs)]
45    pub enum Error {
46        #[error(transparent)]
47        Lookup(#[from] crate::lookup::existing::Error),
48        #[error(transparent)]
49        Header(#[from] crate::parse::section::header::Error),
50        #[error(transparent)]
51        ValueName(#[from] crate::parse::section::value_name::Error),
52        #[error(transparent)]
53        Span(#[from] crate::parse::span::Error),
54    }
55}
56
57/// Convert ergonomic subsection inputs into an optional owned name.
58pub trait IntoBStringOpt {
59    /// Convert into an optional owned subsection name.
60    fn into_bstring_opt(self) -> Option<bstr::BString>;
61}
62
63/// Additional information about a section.
64#[derive(Clone, Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
65pub struct Metadata {
66    /// The file path of the source, if known.
67    pub path: Option<PathBuf>,
68    /// Where the section is coming from.
69    pub source: crate::Source,
70    /// The levels of indirection of the file, with 0 being a section
71    /// that was directly loaded, and 1 being an `include.path` of a
72    /// level 0 file.
73    pub level: u8,
74    /// The trust-level for the section this meta-data is associated with.
75    pub trust: gix_sec::Trust,
76}
77
78#[derive(Clone, Debug)]
79pub(crate) struct SectionData {
80    pub(crate) header: crate::parse::section::HeaderData,
81    pub(crate) body: section::BodyData,
82    pub(crate) meta: OwnShared<Metadata>,
83    pub(crate) id: SectionId,
84}
85
86/// A fully owned, self-contained configuration section.
87///
88/// Use [`Section::to_ref()`] for read-only access and [`Section::to_mut()`] for mutation. This type is returned when
89/// removing sections from a [`File`][crate::File] and can be inserted again with [`File::push_section()`](crate::File::push_section()).
90#[derive(Clone, Debug)]
91pub struct Section {
92    backing: Vec<u8>,
93    data: SectionData,
94}
95
96/// A section in a git-config file, like `[core]` or `[remote "origin"]`, along with all of its keys.
97///
98/// This is a view into data owned by its [`File`][crate::File].
99#[derive(Copy, Clone, Debug)]
100pub struct SectionRef<'a> {
101    data: &'a SectionData,
102    backing: &'a [u8],
103}
104
105/// A strongly typed index into some range.
106#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Clone, Copy)]
107pub(crate) struct Index(pub(crate) usize);
108
109impl Add<Size> for Index {
110    type Output = Self;
111
112    fn add(self, rhs: Size) -> Self::Output {
113        Self(self.0 + rhs.0)
114    }
115}
116
117/// A strongly typed a size.
118#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Clone, Copy)]
119pub(crate) struct Size(pub(crate) usize);
120
121impl AddAssign<usize> for Size {
122    fn add_assign(&mut self, rhs: usize) {
123        self.0 += rhs;
124    }
125}
126
127/// The section ID is a monotonically increasing ID used to refer to section bodies.
128/// This value does not imply any ordering between sections, as new sections
129/// with higher section IDs may be in between lower ID sections after `File` mutation.
130///
131/// We need to use a section id because `git-config` permits sections with
132/// identical names, making it ambiguous when used in maps, for instance.
133///
134/// This id guaranteed to be unique, but not guaranteed to be compact. In other
135/// words, it's possible that a section may have an ID of 3 but the next section
136/// has an ID of 5 as 4 was deleted.
137#[derive(PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord, Debug)]
138pub struct SectionId(pub(crate) usize);
139
140impl Default for SectionId {
141    fn default() -> Self {
142        SectionId(usize::MAX)
143    }
144}
145
146/// All section ids referred to by a section name, in file order within each list.
147#[derive(Default, PartialEq, Eq, Clone, Debug)]
148pub(crate) struct SectionLookup {
149    without_subsection: Vec<SectionId>,
150    by_subsection: HashMap<BString, Vec<SectionId>>,
151}
152#[cfg(test)]
153mod tests;
154mod write;