use crate::file::error::GitConfigError;use crate::file::Index;use crate::parser::{Event, Key};use crate::values::{normalize_cow, normalize_vec};use std::borrow::Cow;use std::convert::TryFrom;use std::ops::{Deref, Range}; /// A opaque type that represents a mutable reference to a section.#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]pub struct MutableSection<'borrow, 'event> { section: &'borrow mut SectionBody<'event>, implicit_newline: bool, whitespace: usize,} impl<'borrow, 'event> MutableSection<'borrow, 'event> { /// Adds an entry to the end of this section. pub fn push(&mut self, key: Key<'event>, value: Cow<'event, [u8]>) { if self.whitespace > 0 { self.section .0 .push(Event::Whitespace(" ".repeat(self.whitespace).into())); } self.section.0.push(Event::Key(key)); self.section.0.push(Event::KeyValueSeparator); self.section.0.push(Event::Value(value)); if self.implicit_newline { self.section.0.push(Event::Newline("\n".into())); } } /// Removes all events until a key value pair is removed. This will also /// remove the whitespace preceding the key value pair, if any is found. pub fn pop(&mut self) -> Option<(Key, Cow<'event, [u8]>)> { let mut values = vec![]; // events are popped in reverse order while let Some(e) = self.section.0.pop() { match e { Event::Key(k) => { // pop leading whitespace if let Some(Event::Whitespace(_)) = self.section.0.last() { self.section.0.pop(); } if values.len() == 1 { let value = values.pop().expect("vec is non-empty but popped to empty value"); return Some((k, normalize_cow(value))); } return Some(( k, normalize_vec(values.into_iter().rev().flat_map(|v: Cow<[u8]>| v.to_vec()).collect()), )); } Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => values.push(v), _ => (), } } None } /// Sets the last key value pair if it exists, or adds the new value. /// Returns the previous value if it replaced a value, or None if it adds /// the value. pub fn set(&mut self, key: Key<'event>, value: Cow<'event, [u8]>) -> Option<Cow<'event, [u8]>> { let range = self.get_value_range_by_key(&key); if range.is_empty() { self.push(key, value); return None; } let range_start = range.start; let ret = self.remove_internal(range); self.section.0.insert(range_start, Event::Value(value)); Some(ret) } /// Removes the latest value by key and returns it, if it exists. pub fn remove(&mut self, key: &Key<'event>) -> Option<Cow<'event, [u8]>> { let range = self.get_value_range_by_key(key); if range.is_empty() { return None; } Some(self.remove_internal(range)) } /// Performs the removal, assuming the range is valid. This is used to /// avoid duplicating searching for the range in [`Self::set`]. fn remove_internal(&mut self, range: Range<usize>) -> Cow<'event, [u8]> { self.section .0 .drain(range) .fold(Cow::<[u8]>::Owned(vec![]), |acc, e| match e { Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => { // This is fine because we start out with an owned // variant, so we never actually clone the // accumulator. let mut acc = acc.into_owned(); acc.extend(&*v); Cow::Owned(acc) } _ => acc, }) } /// Adds a new line event. Note that you don't need to call this unless /// you've disabled implicit newlines. #[inline] pub fn push_newline(&mut self) { self.section.0.push(Event::Newline("\n".into())); } /// Enables or disables automatically adding newline events after adding /// a value. This is enabled by default. #[inline] pub fn implicit_newline(&mut self, on: bool) { self.implicit_newline = on; } /// Sets the number of spaces before the start of a key value. By default, /// this is set to two. Set to 0 to disable adding whitespace before a key /// value. #[inline] pub fn set_whitespace(&mut self, num: usize) { self.whitespace = num; } /// Returns the number of whitespace this section will insert before the /// beginning of a key. #[inline] #[must_use] pub const fn whitespace(&self) -> usize { self.whitespace }} // Internal methods that may require exact indices for faster operations.impl<'borrow, 'event> MutableSection<'borrow, 'event> { #[inline] pub(super) fn new(section: &'borrow mut SectionBody<'event>) -> Self { Self { section, implicit_newline: true, whitespace: 2, } } pub(super) fn get<'key>( &self, key: &Key<'key>, start: Index, end: Index, ) -> Result<Cow<'_, [u8]>, GitConfigError<'key>> { let mut found_key = false; let mut latest_value = None; let mut partial_value = None; // section_id is guaranteed to exist in self.sections, else we have a // violated invariant. for event in &self.section.0[start.0..=end.0] { match event { Event::Key(event_key) if event_key == key => found_key = true, Event::Value(v) if found_key => { found_key = false; // Clones the Cow, doesn't copy underlying value if borrowed latest_value = Some(v.clone()); } Event::ValueNotDone(v) if found_key => { latest_value = None; partial_value = Some((*v).to_vec()); } Event::ValueDone(v) if found_key => { found_key = false; partial_value.as_mut().unwrap().extend(&**v); } _ => (), } } latest_value .map(normalize_cow) .or_else(|| partial_value.map(normalize_vec)) .ok_or(GitConfigError::KeyDoesNotExist) } #[inline] pub(super) fn delete(&mut self, start: Index, end: Index) { self.section.0.drain(start.0..=end.0); } pub(super) fn set_internal(&mut self, index: Index, key: Key<'event>, value: Vec<u8>) { self.section.0.insert(index.0, Event::Value(Cow::Owned(value))); self.section.0.insert(index.0, Event::KeyValueSeparator); self.section.0.insert(index.0, Event::Key(key)); }} impl<'event> Deref for MutableSection<'_, 'event> { type Target = SectionBody<'event>; #[inline] fn deref(&self) -> &Self::Target { self.section }} /// A opaque type that represents a section body.#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Debug, Default)]pub struct SectionBody<'event>(Vec<Event<'event>>); impl<'event> SectionBody<'event> { pub(super) fn as_ref(&self) -> &[Event<'_>] { &self.0 } pub(super) fn as_mut(&mut self) -> &mut Vec<Event<'event>> { &mut self.0 }} impl<'event> SectionBody<'event> { /// Constructs a new empty section body. #[inline] pub(super) fn new() -> Self { Self::default() } /// Retrieves the last matching value in a section with the given key. /// Returns None if the key was not found. // We hit this lint because of the unreachable!() call may panic, but this // is a clippy bug (rust-clippy#6699), so we allow this lint for this // function. #[allow(clippy::missing_panics_doc)] #[must_use] pub fn value(&self, key: &Key) -> Option<Cow<'event, [u8]>> { let range = self.get_value_range_by_key(key); if range.is_empty() { return None; } if range.end - range.start == 1 { return self.0.get(range.start).map(|e| match e { Event::Value(v) => v.clone(), // range only has one element so we know it's a value event, so // it's impossible to reach this code. _ => unreachable!(), }); } Some(normalize_cow(self.0[range].iter().fold( Cow::<[u8]>::Owned(vec![]), |acc, e| match e { Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => { // This is fine because we start out with an owned // variant, so we never actually clone the // accumulator. let mut acc = acc.into_owned(); acc.extend(&**v); Cow::Owned(acc) } _ => acc, }, ))) } /// Retrieves the last matching value in a section with the given key, and /// attempts to convert the value into the provided type. /// /// # Errors /// /// Returns an error if the key was not found, or if the conversion failed. #[inline] pub fn value_as<T: TryFrom<Cow<'event, [u8]>>>(&self, key: &Key) -> Result<T, GitConfigError<'event>> { T::try_from(self.value(key).ok_or(GitConfigError::KeyDoesNotExist)?) .map_err(|_| GitConfigError::FailedConversion) } /// Retrieves all values that have the provided key name. This may return /// an empty vec, which implies there was values with the provided key. #[must_use] pub fn values(&self, key: &Key) -> Vec<Cow<'event, [u8]>> { let mut values = vec![]; let mut found_key = false; let mut partial_value = None; // This can iterate forwards because we need to iterate over the whole // section anyways for event in &self.0 { match event { Event::Key(event_key) if event_key == key => found_key = true, Event::Value(v) if found_key => { found_key = false; // Clones the Cow, doesn't copy underlying value if borrowed values.push(normalize_cow(v.clone())); partial_value = None; } Event::ValueNotDone(v) if found_key => { partial_value = Some((*v).to_vec()); } Event::ValueDone(v) if found_key => { found_key = false; let mut value = partial_value .take() .expect("ValueDone event called before ValueNotDone"); value.extend(&**v); values.push(normalize_cow(Cow::Owned(value))); } _ => (), } } values } /// Retrieves all values that have the provided key name. This may return /// an empty vec, which implies there was values with the provided key. /// /// # Errors /// /// Returns an error if the conversion failed. #[inline] pub fn values_as<T: TryFrom<Cow<'event, [u8]>>>(&self, key: &Key) -> Result<Vec<T>, GitConfigError<'event>> { self.values(key) .into_iter() .map(T::try_from) .collect::<Result<Vec<T>, _>>() .map_err(|_| GitConfigError::FailedConversion) } /// Returns an iterator visiting all keys in order. #[inline] pub fn keys(&self) -> impl Iterator<Item = &Key<'event>> { self.0 .iter() .filter_map(|e| if let Event::Key(k) = e { Some(k) } else { None }) } /// Checks if the section contains the provided key. #[must_use] pub fn contains_key(&self, key: &Key) -> bool { for e in &self.0 { if let Event::Key(k) = e { if k == key { return true; } } } false } /// Returns the number of entries in the section. #[inline] #[must_use] pub fn len(&self) -> usize { self.0.iter().filter(|e| matches!(e, Event::Key(_))).count() } /// Returns if the section is empty. #[inline] #[must_use] pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Returns the the range containing the value events for the section. /// If the value is not found, then this returns an empty range. fn get_value_range_by_key(&self, key: &Key<'event>) -> Range<usize> { let mut values_start = 0; // value end needs to be offset by one so that the last value's index // is included in the range let mut values_end = 0; for (i, e) in self.0.iter().enumerate().rev() { match e { Event::Key(k) => { if k == key { break; } values_start = 0; values_end = 0; } Event::Value(_) => { values_end = i + 1; values_start = i; } Event::ValueNotDone(_) | Event::ValueDone(_) => { if values_end == 0 { values_end = i + 1; } else { values_start = i; } } _ => (), } } values_start..values_end }} impl<'event> From<Vec<Event<'event>>> for SectionBody<'event> { #[inline] fn from(e: Vec<Event<'event>>) -> Self { Self(e) }}
use crate::file::error::GitConfigError;
use crate::file::Index;
use crate::parser::{Event, Key};
use crate::values::{normalize_cow, normalize_vec};
use std::borrow::Cow;
use std::convert::TryFrom;
use std::ops::{Deref, Range};
/// A opaque type that represents a mutable reference to a section.
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct MutableSection<'borrow, 'event> {
section: &'borrow mut SectionBody<'event>,
implicit_newline: bool,
whitespace: usize,
}
impl<'borrow, 'event> MutableSection<'borrow, 'event> {
/// Adds an entry to the end of this section.
pub fn push(&mut self, key: Key<'event>, value: Cow<'event, [u8]>) {
if self.whitespace > 0 {
self.section
.0
.push(Event::Whitespace(" ".repeat(self.whitespace).into()));
}
self.section.0.push(Event::Key(key));
self.section.0.push(Event::KeyValueSeparator);
self.section.0.push(Event::Value(value));
if self.implicit_newline {
self.section.0.push(Event::Newline("\n".into()));
}
}
/// Removes all events until a key value pair is removed. This will also
/// remove the whitespace preceding the key value pair, if any is found.
pub fn pop(&mut self) -> Option<(Key, Cow<'event, [u8]>)> {
let mut values = vec![];
// events are popped in reverse order
while let Some(e) = self.section.0.pop() {
match e {
Event::Key(k) => {
// pop leading whitespace
if let Some(Event::Whitespace(_)) = self.section.0.last() {
self.section.0.pop();
}
if values.len() == 1 {
let value = values.pop().expect("vec is non-empty but popped to empty value");
return Some((k, normalize_cow(value)));
}
return Some((
k,
normalize_vec(values.into_iter().rev().flat_map(|v: Cow<[u8]>| v.to_vec()).collect()),
));
}
Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => values.push(v),
_ => (),
}
}
None
}
/// Sets the last key value pair if it exists, or adds the new value.
/// Returns the previous value if it replaced a value, or None if it adds
/// the value.
pub fn set(&mut self, key: Key<'event>, value: Cow<'event, [u8]>) -> Option<Cow<'event, [u8]>> {
let range = self.get_value_range_by_key(&key);
if range.is_empty() {
self.push(key, value);
return None;
}
let range_start = range.start;
let ret = self.remove_internal(range);
self.section.0.insert(range_start, Event::Value(value));
Some(ret)
}
/// Removes the latest value by key and returns it, if it exists.
pub fn remove(&mut self, key: &Key<'event>) -> Option<Cow<'event, [u8]>> {
let range = self.get_value_range_by_key(key);
if range.is_empty() {
return None;
}
Some(self.remove_internal(range))
}
/// Performs the removal, assuming the range is valid. This is used to
/// avoid duplicating searching for the range in [`Self::set`].
fn remove_internal(&mut self, range: Range<usize>) -> Cow<'event, [u8]> {
self.section
.0
.drain(range)
.fold(Cow::<[u8]>::Owned(vec![]), |acc, e| match e {
Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => {
// This is fine because we start out with an owned
// variant, so we never actually clone the
// accumulator.
let mut acc = acc.into_owned();
acc.extend(&*v);
Cow::Owned(acc)
}
_ => acc,
})
}
/// Adds a new line event. Note that you don't need to call this unless
/// you've disabled implicit newlines.
#[inline]
pub fn push_newline(&mut self) {
self.section.0.push(Event::Newline("\n".into()));
}
/// Enables or disables automatically adding newline events after adding
/// a value. This is enabled by default.
#[inline]
pub fn implicit_newline(&mut self, on: bool) {
self.implicit_newline = on;
}
/// Sets the number of spaces before the start of a key value. By default,
/// this is set to two. Set to 0 to disable adding whitespace before a key
/// value.
#[inline]
pub fn set_whitespace(&mut self, num: usize) {
self.whitespace = num;
}
/// Returns the number of whitespace this section will insert before the
/// beginning of a key.
#[inline]
#[must_use]
pub const fn whitespace(&self) -> usize {
self.whitespace
}
}
// Internal methods that may require exact indices for faster operations.
impl<'borrow, 'event> MutableSection<'borrow, 'event> {
#[inline]
pub(super) fn new(section: &'borrow mut SectionBody<'event>) -> Self {
Self {
section,
implicit_newline: true,
whitespace: 2,
}
}
pub(super) fn get<'key>(
&self,
key: &Key<'key>,
start: Index,
end: Index,
) -> Result<Cow<'_, [u8]>, GitConfigError<'key>> {
let mut found_key = false;
let mut latest_value = None;
let mut partial_value = None;
// section_id is guaranteed to exist in self.sections, else we have a
// violated invariant.
for event in &self.section.0[start.0..=end.0] {
match event {
Event::Key(event_key) if event_key == key => found_key = true,
Event::Value(v) if found_key => {
found_key = false;
// Clones the Cow, doesn't copy underlying value if borrowed
latest_value = Some(v.clone());
}
Event::ValueNotDone(v) if found_key => {
latest_value = None;
partial_value = Some((*v).to_vec());
}
Event::ValueDone(v) if found_key => {
found_key = false;
partial_value.as_mut().unwrap().extend(&**v);
}
_ => (),
}
}
latest_value
.map(normalize_cow)
.or_else(|| partial_value.map(normalize_vec))
.ok_or(GitConfigError::KeyDoesNotExist)
}
#[inline]
pub(super) fn delete(&mut self, start: Index, end: Index) {
self.section.0.drain(start.0..=end.0);
}
pub(super) fn set_internal(&mut self, index: Index, key: Key<'event>, value: Vec<u8>) {
self.section.0.insert(index.0, Event::Value(Cow::Owned(value)));
self.section.0.insert(index.0, Event::KeyValueSeparator);
self.section.0.insert(index.0, Event::Key(key));
}
}
impl<'event> Deref for MutableSection<'_, 'event> {
type Target = SectionBody<'event>;
#[inline]
fn deref(&self) -> &Self::Target {
self.section
}
}
/// A opaque type that represents a section body.
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Debug, Default)]
pub struct SectionBody<'event>(Vec<Event<'event>>);
impl<'event> SectionBody<'event> {
pub(super) fn as_ref(&self) -> &[Event<'_>] {
&self.0
}
pub(super) fn as_mut(&mut self) -> &mut Vec<Event<'event>> {
&mut self.0
}
}
impl<'event> SectionBody<'event> {
/// Constructs a new empty section body.
#[inline]
pub(super) fn new() -> Self {
Self::default()
}
/// Retrieves the last matching value in a section with the given key.
/// Returns None if the key was not found.
// We hit this lint because of the unreachable!() call may panic, but this
// is a clippy bug (rust-clippy#6699), so we allow this lint for this
// function.
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn value(&self, key: &Key) -> Option<Cow<'event, [u8]>> {
let range = self.get_value_range_by_key(key);
if range.is_empty() {
return None;
}
if range.end - range.start == 1 {
return self.0.get(range.start).map(|e| match e {
Event::Value(v) => v.clone(),
// range only has one element so we know it's a value event, so
// it's impossible to reach this code.
_ => unreachable!(),
});
}
Some(normalize_cow(self.0[range].iter().fold(
Cow::<[u8]>::Owned(vec![]),
|acc, e| match e {
Event::Value(v) | Event::ValueNotDone(v) | Event::ValueDone(v) => {
// This is fine because we start out with an owned
// variant, so we never actually clone the
// accumulator.
let mut acc = acc.into_owned();
acc.extend(&**v);
Cow::Owned(acc)
}
_ => acc,
},
)))
}
/// Retrieves the last matching value in a section with the given key, and
/// attempts to convert the value into the provided type.
///
/// # Errors
///
/// Returns an error if the key was not found, or if the conversion failed.
#[inline]
pub fn value_as<T: TryFrom<Cow<'event, [u8]>>>(&self, key: &Key) -> Result<T, GitConfigError<'event>> {
T::try_from(self.value(key).ok_or(GitConfigError::KeyDoesNotExist)?)
.map_err(|_| GitConfigError::FailedConversion)
}
/// Retrieves all values that have the provided key name. This may return
/// an empty vec, which implies there was values with the provided key.
#[must_use]
pub fn values(&self, key: &Key) -> Vec<Cow<'event, [u8]>> {
let mut values = vec![];
let mut found_key = false;
let mut partial_value = None;
// This can iterate forwards because we need to iterate over the whole
// section anyways
for event in &self.0 {
match event {
Event::Key(event_key) if event_key == key => found_key = true,
Event::Value(v) if found_key => {
found_key = false;
// Clones the Cow, doesn't copy underlying value if borrowed
values.push(normalize_cow(v.clone()));
partial_value = None;
}
Event::ValueNotDone(v) if found_key => {
partial_value = Some((*v).to_vec());
}
Event::ValueDone(v) if found_key => {
found_key = false;
let mut value = partial_value
.take()
.expect("ValueDone event called before ValueNotDone");
value.extend(&**v);
values.push(normalize_cow(Cow::Owned(value)));
}
_ => (),
}
}
values
}
/// Retrieves all values that have the provided key name. This may return
/// an empty vec, which implies there was values with the provided key.
///
/// # Errors
///
/// Returns an error if the conversion failed.
#[inline]
pub fn values_as<T: TryFrom<Cow<'event, [u8]>>>(&self, key: &Key) -> Result<Vec<T>, GitConfigError<'event>> {
self.values(key)
.into_iter()
.map(T::try_from)
.collect::<Result<Vec<T>, _>>()
.map_err(|_| GitConfigError::FailedConversion)
}
/// Returns an iterator visiting all keys in order.
#[inline]
pub fn keys(&self) -> impl Iterator<Item = &Key<'event>> {
self.0
.iter()
.filter_map(|e| if let Event::Key(k) = e { Some(k) } else { None })
}
/// Checks if the section contains the provided key.
#[must_use]
pub fn contains_key(&self, key: &Key) -> bool {
for e in &self.0 {
if let Event::Key(k) = e {
if k == key {
return true;
}
}
}
false
}
/// Returns the number of entries in the section.
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.0.iter().filter(|e| matches!(e, Event::Key(_))).count()
}
/// Returns if the section is empty.
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns the the range containing the value events for the section.
/// If the value is not found, then this returns an empty range.
fn get_value_range_by_key(&self, key: &Key<'event>) -> Range<usize> {
let mut values_start = 0;
// value end needs to be offset by one so that the last value's index
// is included in the range
let mut values_end = 0;
for (i, e) in self.0.iter().enumerate().rev() {
match e {
Event::Key(k) => {
if k == key {
break;
}
values_start = 0;
values_end = 0;
}
Event::Value(_) => {
values_end = i + 1;
values_start = i;
}
Event::ValueNotDone(_) | Event::ValueDone(_) => {
if values_end == 0 {
values_end = i + 1;
} else {
values_start = i;
}
}
_ => (),
}
}
values_start..values_end
}
}
impl<'event> From<Vec<Event<'event>>> for SectionBody<'event> {
#[inline]
fn from(e: Vec<Event<'event>>) -> Self {
Self(e)
}
}