]> git.proxmox.com Git - rustc.git/blame - vendor/gix-config/src/file/section/mod.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / vendor / gix-config / src / file / section / mod.rs
CommitLineData
0a29b90c
FG
1use std::{borrow::Cow, ops::Deref};
2
3use bstr::{BStr, BString, ByteSlice};
4use smallvec::SmallVec;
5
6use crate::{
7 file,
8 file::{Metadata, Section, SectionMut},
9 parse,
10 parse::{section, Event},
11};
12
13pub(crate) mod body;
14pub use body::{Body, BodyIter};
15use gix_features::threading::OwnShared;
16
17use crate::file::{
18 write::{extract_newline, platform_newline},
19 SectionId,
20};
21
22impl<'a> Deref for Section<'a> {
23 type Target = Body<'a>;
24
25 fn deref(&self) -> &Self::Target {
26 &self.body
27 }
28}
29
30/// Instantiation and conversion
31impl<'a> Section<'a> {
32 /// Create a new section with the given `name` and optional, `subsection`, `meta`-data and an empty body.
33 pub fn new(
34 name: impl Into<Cow<'a, str>>,
35 subsection: impl Into<Option<Cow<'a, BStr>>>,
36 meta: impl Into<OwnShared<file::Metadata>>,
37 ) -> Result<Self, parse::section::header::Error> {
38 Ok(Section {
39 header: parse::section::Header::new(name, subsection)?,
40 body: Default::default(),
41 meta: meta.into(),
42 id: SectionId::default(),
43 })
44 }
45}
46
47/// Access
48impl<'a> Section<'a> {
49 /// Return our header.
50 pub fn header(&self) -> &section::Header<'a> {
51 &self.header
52 }
53
54 /// Return the unique `id` of the section, for use with the `*_by_id()` family of methods
fe692bf9 55 /// in [`gix_config::File`][crate::File].
0a29b90c
FG
56 pub fn id(&self) -> SectionId {
57 self.id
58 }
59
60 /// Return our body, containing all keys and values.
61 pub fn body(&self) -> &Body<'a> {
62 &self.body
63 }
64
65 /// Serialize this type into a `BString` for convenience.
66 ///
67 /// Note that `to_string()` can also be used, but might not be lossless.
68 #[must_use]
69 pub fn to_bstring(&self) -> BString {
70 let mut buf = Vec::new();
71 self.write_to(&mut buf).expect("io error impossible");
72 buf.into()
73 }
74
75 /// Stream ourselves to the given `out`, in order to reproduce this section mostly losslessly
76 /// as it was parsed.
77 pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> {
78 self.header.write_to(&mut out)?;
79
80 if self.body.0.is_empty() {
81 return Ok(());
82 }
83
84 let nl = self
85 .body
86 .as_ref()
87 .iter()
88 .find_map(extract_newline)
89 .unwrap_or_else(|| platform_newline());
90
91 if !self
92 .body
93 .as_ref()
94 .iter()
95 .take_while(|e| !matches!(e, Event::SectionKey(_)))
96 .any(|e| e.to_bstr_lossy().contains_str(nl))
97 {
98 out.write_all(nl)?;
99 }
100
101 let mut saw_newline_after_value = true;
102 let mut in_key_value_pair = false;
103 for (idx, event) in self.body.as_ref().iter().enumerate() {
104 match event {
105 Event::SectionKey(_) => {
106 if !saw_newline_after_value {
107 out.write_all(nl)?;
108 }
109 saw_newline_after_value = false;
110 in_key_value_pair = true;
111 }
112 Event::Newline(_) if !in_key_value_pair => {
113 saw_newline_after_value = true;
114 }
115 Event::Value(_) | Event::ValueDone(_) => {
116 in_key_value_pair = false;
117 }
118 _ => {}
119 }
120 event.write_to(&mut out)?;
121 if let Event::ValueNotDone(_) = event {
122 if self
123 .body
124 .0
125 .get(idx + 1)
126 .filter(|e| matches!(e, Event::Newline(_)))
127 .is_none()
128 {
129 out.write_all(nl)?;
130 }
131 }
132 }
133 Ok(())
134 }
135
136 /// Return additional information about this sections origin.
137 pub fn meta(&self) -> &Metadata {
138 &self.meta
139 }
140
141 /// Returns a mutable version of this section for adjustment of values.
142 pub fn to_mut(&mut self, newline: SmallVec<[u8; 2]>) -> SectionMut<'_, 'a> {
143 SectionMut::new(self, newline)
144 }
145}