summaryrefslogtreecommitdiffstats
path: root/vendor/gix-config/src/file/section/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-config/src/file/section/mod.rs')
-rw-r--r--vendor/gix-config/src/file/section/mod.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/vendor/gix-config/src/file/section/mod.rs b/vendor/gix-config/src/file/section/mod.rs
new file mode 100644
index 000000000..e8e331084
--- /dev/null
+++ b/vendor/gix-config/src/file/section/mod.rs
@@ -0,0 +1,145 @@
+use std::{borrow::Cow, ops::Deref};
+
+use bstr::{BStr, BString, ByteSlice};
+use smallvec::SmallVec;
+
+use crate::{
+ file,
+ file::{Metadata, Section, SectionMut},
+ parse,
+ parse::{section, Event},
+};
+
+pub(crate) mod body;
+pub use body::{Body, BodyIter};
+use gix_features::threading::OwnShared;
+
+use crate::file::{
+ write::{extract_newline, platform_newline},
+ SectionId,
+};
+
+impl<'a> Deref for Section<'a> {
+ type Target = Body<'a>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.body
+ }
+}
+
+/// Instantiation and conversion
+impl<'a> Section<'a> {
+ /// Create a new section with the given `name` and optional, `subsection`, `meta`-data and an empty body.
+ pub fn new(
+ name: impl Into<Cow<'a, str>>,
+ subsection: impl Into<Option<Cow<'a, BStr>>>,
+ meta: impl Into<OwnShared<file::Metadata>>,
+ ) -> Result<Self, parse::section::header::Error> {
+ Ok(Section {
+ header: parse::section::Header::new(name, subsection)?,
+ body: Default::default(),
+ meta: meta.into(),
+ id: SectionId::default(),
+ })
+ }
+}
+
+/// Access
+impl<'a> Section<'a> {
+ /// Return our header.
+ pub fn header(&self) -> &section::Header<'a> {
+ &self.header
+ }
+
+ /// Return the unique `id` of the section, for use with the `*_by_id()` family of methods
+ /// in [gix_config::File][crate::File].
+ pub fn id(&self) -> SectionId {
+ self.id
+ }
+
+ /// Return our body, containing all keys and values.
+ pub fn body(&self) -> &Body<'a> {
+ &self.body
+ }
+
+ /// Serialize this type into a `BString` for convenience.
+ ///
+ /// Note that `to_string()` can also be used, but might not be lossless.
+ #[must_use]
+ pub fn to_bstring(&self) -> BString {
+ let mut buf = Vec::new();
+ self.write_to(&mut buf).expect("io error impossible");
+ buf.into()
+ }
+
+ /// Stream ourselves to the given `out`, in order to reproduce this section mostly losslessly
+ /// as it was parsed.
+ pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> {
+ self.header.write_to(&mut out)?;
+
+ if self.body.0.is_empty() {
+ return Ok(());
+ }
+
+ let nl = self
+ .body
+ .as_ref()
+ .iter()
+ .find_map(extract_newline)
+ .unwrap_or_else(|| platform_newline());
+
+ if !self
+ .body
+ .as_ref()
+ .iter()
+ .take_while(|e| !matches!(e, Event::SectionKey(_)))
+ .any(|e| e.to_bstr_lossy().contains_str(nl))
+ {
+ out.write_all(nl)?;
+ }
+
+ let mut saw_newline_after_value = true;
+ let mut in_key_value_pair = false;
+ for (idx, event) in self.body.as_ref().iter().enumerate() {
+ match event {
+ Event::SectionKey(_) => {
+ if !saw_newline_after_value {
+ out.write_all(nl)?;
+ }
+ saw_newline_after_value = false;
+ in_key_value_pair = true;
+ }
+ Event::Newline(_) if !in_key_value_pair => {
+ saw_newline_after_value = true;
+ }
+ Event::Value(_) | Event::ValueDone(_) => {
+ in_key_value_pair = false;
+ }
+ _ => {}
+ }
+ event.write_to(&mut out)?;
+ if let Event::ValueNotDone(_) = event {
+ if self
+ .body
+ .0
+ .get(idx + 1)
+ .filter(|e| matches!(e, Event::Newline(_)))
+ .is_none()
+ {
+ out.write_all(nl)?;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ /// Return additional information about this sections origin.
+ pub fn meta(&self) -> &Metadata {
+ &self.meta
+ }
+
+ /// Returns a mutable version of this section for adjustment of values.
+ pub fn to_mut(&mut self, newline: SmallVec<[u8; 2]>) -> SectionMut<'_, 'a> {
+ SectionMut::new(self, newline)
+ }
+}