multablemultivalue

This commit is contained in:
Edward Shen 2021-03-02 14:34:18 -05:00
parent 559afb01fa
commit cbb970c293
Signed by: edward
GPG key ID: 19182661E818369F

View file

@ -92,6 +92,13 @@ impl MutableValue<'_, '_, '_> {
.ok_or(GitConfigError::KeyDoesNotExist(self.key)) .ok_or(GitConfigError::KeyDoesNotExist(self.key))
} }
/// Update the value to the provided one. This modifies the value such that
/// the Value event(s) are replaced with a single new event containing the
/// new value.
pub fn set_string(&mut self, input: String) {
self.set_bytes(input.into_bytes());
}
/// Update the value to the provided one. This modifies the value such that /// Update the value to the provided one. This modifies the value such that
/// the Value event(s) are replaced with a single new event containing the /// the Value event(s) are replaced with a single new event containing the
/// new value. /// new value.
@ -101,20 +108,116 @@ impl MutableValue<'_, '_, '_> {
self.section self.section
.insert(self.index, Event::Value(Cow::Owned(input))); .insert(self.index, Event::Value(Cow::Owned(input)));
} }
}
/// Update the value to the provided one. This modifies the value such that pub struct MutableMultiValue<'borrow, 'lookup, 'event> {
/// the Value event(s) are replaced with a single new event containing the section: &'borrow mut HashMap<SectionId, Vec<Event<'event>>>,
/// new value. key: &'lookup str,
pub fn set_string(&mut self, input: String) { indices_and_sizes: Vec<(SectionId, usize, usize)>,
self.set_bytes(input.into_bytes()); }
impl<'event> MutableMultiValue<'_, '_, 'event> {
/// Returns the actual value. This is computed each time this is called, so
/// it's best to reuse this value or own it if an allocation is acceptable.
pub fn value(&self) -> Result<Vec<Cow<'_, [u8]>>, GitConfigError> {
let mut found_key = false;
let mut values = vec![];
let mut partial_value = None;
// section_id is guaranteed to exist in self.sections, else we have a
// violated invariant.
for (section_id, index, size) in &self.indices_and_sizes {
for event in &self.section.get(section_id).unwrap()[*index..*size] {
match event {
Event::Key(event_key) if *event_key == self.key => found_key = true,
Event::Value(v) if found_key => {
found_key = false;
values.push(normalize_bytes(v.borrow()));
}
Event::ValueNotDone(v) if found_key => {
partial_value = Some((*v).to_vec());
}
Event::ValueDone(v) if found_key => {
found_key = false;
partial_value.as_mut().unwrap().extend(&**v);
values.push(normalize_vec(partial_value.take().unwrap()));
}
_ => (),
}
} }
} }
// pub struct MutableMultiValue<'borrow, 'lookup, 'event> { if values.is_empty() {
// section: &'borrow mut Vec<Event<'event>>, return Err(GitConfigError::KeyDoesNotExist(self.key));
// key: &'lookup str, }
// indices_and_sizes: Vec<(usize, usize)>,
// } Ok(values)
}
pub fn len(&self) -> usize {
self.indices_and_sizes.len()
}
pub fn is_empty(&self) -> bool {
self.indices_and_sizes.is_empty()
}
pub fn set_string(&mut self, index: usize, input: String) {
self.set_bytes(index, input.into_bytes())
}
pub fn set_bytes(&mut self, index: usize, input: Vec<u8>) {
self.set_value(index, Cow::Owned(input))
}
pub fn set_value(&mut self, index: usize, input: Cow<'event, [u8]>) {
let (section_id, index, size) = &mut self.indices_and_sizes[index];
self.section
.get_mut(section_id)
.unwrap()
.drain(*index..*index + *size);
*size = 1;
self.section
.get_mut(section_id)
.unwrap()
.insert(*index, Event::Value(input));
}
pub fn set_values(&mut self, input: impl Iterator<Item = Cow<'event, [u8]>>) {
for ((section_id, index, size), value) in self.indices_and_sizes.iter_mut().zip(input) {
self.section
.get_mut(section_id)
.unwrap()
.drain(*index..*index + *size);
*size = 1;
self.section
.get_mut(section_id)
.unwrap()
.insert(*index, Event::Value(value));
}
}
pub fn set_string_all(&mut self, input: String) {
self.set_bytes_all(input.into_bytes())
}
pub fn set_bytes_all(&mut self, input: Vec<u8>) {
self.set_values_all(Cow::Owned(input))
}
pub fn set_values_all(&mut self, input: Cow<'event, [u8]>) {
for (section_id, index, size) in &mut self.indices_and_sizes {
self.section
.get_mut(section_id)
.unwrap()
.drain(*index..*index + *size);
*size = 1;
self.section
.get_mut(section_id)
.unwrap()
.insert(*index, Event::Value(input.clone()));
}
}
}
/// High level `git-config` reader and writer. /// High level `git-config` reader and writer.
/// ///
@ -317,7 +420,7 @@ impl<'event> GitConfig<'event> {
// section_id is guaranteed to exist in self.sections, else we have a // section_id is guaranteed to exist in self.sections, else we have a
// violated invariant. // violated invariant.
for event in self.sections.get(&section_id).unwrap() { for event in self.sections.get(section_id).unwrap() {
match event { match event {
Event::Key(event_key) if *event_key == key => found_key = true, Event::Key(event_key) if *event_key == key => found_key = true,
Event::Value(v) if found_key => { Event::Value(v) if found_key => {
@ -336,10 +439,8 @@ impl<'event> GitConfig<'event> {
_ => (), _ => (),
} }
} }
if let Some(v) = latest_value.or_else(|| partial_value.map(normalize_vec)) {
match latest_value.or_else(|| partial_value.map(normalize_vec)) { return Ok(v);
Some(v) => return Ok(v),
None => (),
} }
} }
@ -369,7 +470,7 @@ impl<'event> GitConfig<'event> {
let mut size = 0; let mut size = 0;
let mut index = 0; let mut index = 0;
let mut found_key = false; let mut found_key = false;
for (i, event) in self.sections.get(&section_id).unwrap().iter().enumerate() { for (i, event) in self.sections.get(section_id).unwrap().iter().enumerate() {
match event { match event {
Event::Key(event_key) if *event_key == key => found_key = true, Event::Key(event_key) if *event_key == key => found_key = true,
Event::Value(_) if found_key => { Event::Value(_) if found_key => {
@ -394,7 +495,7 @@ impl<'event> GitConfig<'event> {
} }
return Ok(MutableValue { return Ok(MutableValue {
section: self.sections.get_mut(&section_id).unwrap(), section: self.sections.get_mut(section_id).unwrap(),
key, key,
size, size,
index, index,
@ -514,9 +615,9 @@ impl<'event> GitConfig<'event> {
/// Cow::Borrowed(b"d") /// Cow::Borrowed(b"d")
/// ] /// ]
/// ); /// );
/// for value in git_config.get_raw_multi_value_mut("core", None, "a")? { ///
/// *value = Cow::Borrowed(b"g"); /// git_config.get_raw_multi_value_mut("core", None, "a")?.set_string_all("g".to_string());
///} ///
/// assert_eq!( /// assert_eq!(
/// git_config.get_raw_multi_value("core", None, "a")?, /// git_config.get_raw_multi_value("core", None, "a")?,
/// vec![ /// vec![
@ -544,42 +645,45 @@ impl<'event> GitConfig<'event> {
section_name: &'lookup str, section_name: &'lookup str,
subsection_name: Option<&'lookup str>, subsection_name: Option<&'lookup str>,
key: &'lookup str, key: &'lookup str,
) -> Result<Vec<&mut Cow<'event, [u8]>>, GitConfigError<'lookup>> { ) -> Result<MutableMultiValue<'_, 'lookup, 'event>, GitConfigError<'lookup>> {
let key = key;
let section_ids = self let section_ids = self
.get_section_ids_by_name_and_subname(section_name, subsection_name)? .get_section_ids_by_name_and_subname(section_name, subsection_name)?
.to_vec(); .to_vec();
let mut indices = vec![];
for section_id in section_ids.iter().rev() {
let mut size = 0;
let mut index = 0;
let mut found_key = false; let mut found_key = false;
let values: Vec<&mut Cow<'event, [u8]>> = self for (i, event) in self.sections.get(section_id).unwrap().iter().enumerate() {
.sections
.iter_mut()
.filter_map(|(k, v)| {
if section_ids.contains(k) {
let mut values = vec![];
for event in v {
match event { match event {
Event::Key(event_key) if *event_key == key => found_key = true, Event::Key(event_key) if *event_key == key => found_key = true,
Event::Value(v) if found_key => { Event::Value(_) if found_key => {
values.push(v); indices.push((*section_id, i, 1));
found_key = false; found_key = false;
} }
Event::ValueNotDone(_) if found_key => {
size = 1;
index = i;
}
Event::ValueDone(_) if found_key => {
found_key = false;
size += 1;
indices.push((*section_id, index, size));
}
_ => (), _ => (),
} }
} }
Some(values)
} else {
None
} }
})
.flatten()
.collect();
// TODO: return mutable entry instead if !indices.is_empty() {
// TODO: support partial values Ok(MutableMultiValue {
if values.is_empty() { section: &mut self.sections,
Err(GitConfigError::KeyDoesNotExist(key)) key,
indices_and_sizes: indices,
})
} else { } else {
Ok(values) Err(GitConfigError::KeyDoesNotExist(key))
} }
} }
@ -717,11 +821,8 @@ impl<'event> GitConfig<'event> {
key: &'lookup str, key: &'lookup str,
new_values: impl Iterator<Item = Cow<'event, [u8]>>, new_values: impl Iterator<Item = Cow<'event, [u8]>>,
) -> Result<(), GitConfigError<'lookup>> { ) -> Result<(), GitConfigError<'lookup>> {
let values = self.get_raw_multi_value_mut(section_name, subsection_name, key)?; self.get_raw_multi_value_mut(section_name, subsection_name, key)
for (old, new) in values.into_iter().zip(new_values) { .map(|mut v| v.set_values(new_values))
*old = new;
}
Ok(())
} }
} }