Skip to content

Commit

Permalink
Merge pull request #8 from Vinnstah/try-append-update
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajjon authored Dec 13, 2023
2 parents b9fe606 + 63b4126 commit 7caf3e2
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/serde_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ pub enum IdentifiedVecOfSerdeFailure {
#[error("Duplicate element at offset {0}")]
DuplicateElementsAtIndex(usize),
}

#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
pub enum Error {
#[error("Element with that id: `{0}` not found in collection")]
ExpectedElementNotPresent(String),
#[error("Duplicate element with same value: `{0}` found")]
ElementWithSameValueFound(String),
#[error("Duplicate element with same ID: `{0}` found")]
ElementWithSameIDFound(String),
}
72 changes: 72 additions & 0 deletions src/vec.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::serde_error::Error;
use std::collections::HashMap;
use std::fmt::{Debug, Display};
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -534,6 +535,59 @@ where
}
}

impl<ID, Element> IdentifiedVec<ID, Element>
where
ID: Eq + Hash + Clone + Debug,
Element: Eq + Debug,
{
/// Try append a new unique member to the end of the `identified_vec`, if the `identified_vec` already contains the Value or ID a Error will be returned.
///
/// - Parameter item: The element to add to the `identified_vec`.
/// - Returns: Either a Ok() with a pair `(inserted, index)`, where `inserted` is a Boolean value indicating whether
/// the operation added a new element, and `index` is the index of `item` in the resulting
/// `identified_vec`. If the given ID already exist `Error::ElementWithSameIDFound` willl be returned and if the value pre-exists within the collection the function call returns `Error::ElementWithSameValueFound`.
/// - Complexity: The operation is expected to perform O(1) copy, hash, and compare operations on
/// the `ID` type, if it implements high-quality hashing.
#[inline]
pub fn try_append_unique_element(&mut self, element: Element) -> Result<(bool, usize), Error> {
let id = self.id(&element);

if let Some(value) = self.get(&id) {
if value == &element {
return Err(Error::ElementWithSameValueFound(format!("{:?}", value)));
} else {
return Err(Error::ElementWithSameIDFound(format!("{:?}", id)));
}
}

Ok(self.append(element))
}
}

impl<ID, Element> IdentifiedVec<ID, Element>
where
ID: Eq + Hash + Clone + Debug,
{
/// Try append a new member to the end of the `identified_vec`, if the `identified_vec` already contains the element a Error will be returned.
///
/// - Parameter item: The element to add to the `identified_vec`.
/// - Returns: Either a Ok() with a pair `(inserted, index)`, where `inserted` is a Boolean value indicating whether
/// the operation added a new element, and `index` is the index of `item` in the resulting
/// `identified_vec`. If the given ID pre-exists within the collection the function call returns `Error::ElementWithSameIDFound`.
/// - Complexity: The operation is expected to perform O(1) copy, hash, and compare operations on
/// the `ID` type, if it implements high-quality hashing.
#[inline]
pub fn try_append_new(&mut self, element: Element) -> Result<(bool, usize), Error> {
let id = self.id(&element);

if self.contains_id(&id) {
return Err(Error::ElementWithSameIDFound(format!("{:#?}", id)));
}

Ok(self.append(element))
}
}

///////////////////////
//// Public Insert ///
///////////////////////
Expand Down Expand Up @@ -606,6 +660,24 @@ where
.expect("Replaced old value");
}

/// Try to update the given element to the `identified_vec` if a element with the same ID is already present.
///
/// - Parameter item: The value to append or replace.
/// - Returns: A Result with either the original element that was replaced by this operation, or a Error, `Error::ExpectedElementNotPresent`, specifying that the expected element is not present within the collection.
/// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare
/// operations on the `ID` type, if it implements high-quality hashing.
#[inline]
pub fn try_update(&mut self, element: Element) -> Result<Element, Error> {
let id = self.id(&element);
if self.get(&id).is_none() {
return Err(Error::ExpectedElementNotPresent(format!("{:#?}", id)));
}

Ok(self
._update_value(element, id)
.expect("Failed to update value"))
}

/// Insert a new member to this identified_vec at the specified index, if the identified_vec doesn't already contain
/// it.
///
Expand Down
90 changes: 89 additions & 1 deletion tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::{cell::RefCell, collections::HashSet, fmt::Debug, ops::Deref};

use identified_vec::{
ConflictResolutionChoice, Identifiable, IdentifiedVec, IdentifiedVecOf,
ConflictResolutionChoice, Error, Identifiable, IdentifiedVec, IdentifiedVecOf,
IdentifiedVecOfSerdeFailure,
};

Expand Down Expand Up @@ -314,6 +314,72 @@ fn append() {
assert_eq!(identified_vec.items(), [1, 2, 3, 4]);
}

#[test]
fn try_append_unique_element() {
let mut identified_vec = SUT::from_iter([1, 2, 3]);
let result = identified_vec.try_append_unique_element(4);
assert!(result.is_ok());
assert_eq!(result.unwrap().1, 3);
assert_eq!(identified_vec.items(), [1, 2, 3, 4]);

let mut identified_vec = SUT::from_iter([1, 2, 3]);
let result = identified_vec.try_append_unique_element(2);
assert!(result.is_err());
assert_eq!(result, Err(Error::ElementWithSameValueFound(format!("2"))));
assert_eq!(identified_vec.items(), [1, 2, 3]);

let mut identified_vec =
IdentifiedVecOf::from_iter([User::blob(), User::blob_jr(), User::blob_sr()]);
let result = identified_vec.try_append_unique_element(User::new(2, "Blob blob Jr"));
assert!(result.is_err());
assert_eq!(result, Err(Error::ElementWithSameIDFound(format!("2"))));
assert_eq!(
identified_vec.items(),
[User::blob(), User::blob_jr(), User::blob_sr()]
);
}

#[test]
fn try_append_new_unique_element() {
let mut identified_vec = SUT::from_iter([1, 2, 3]);
let result = identified_vec.try_append_new(4);
assert!(result.is_ok());
assert_eq!(result.unwrap().1, 3);
assert_eq!(identified_vec.items(), [1, 2, 3, 4]);

let mut identified_vec: Users = IdentifiedVecOf::new();
identified_vec.append(User::blob());
identified_vec.append(User::blob_jr());
identified_vec.append(User::blob_sr());
let result = identified_vec.try_append_new(User::new(4, "Blob Jr Jr"));
assert!(result.is_ok());
assert_eq!(result, Ok((true, 3)));
assert_eq!(
identified_vec.items(),
[
User::blob(),
User::blob_jr(),
User::blob_sr(),
User::new(4, "Blob Jr Jr")
]
);
}

#[test]
fn try_append_element_with_existing_id() {
let mut identified_vec: Users = IdentifiedVecOf::new();
identified_vec.append(User::blob());
identified_vec.append(User::blob_jr());
identified_vec.append(User::blob_sr());
let result = identified_vec.try_append_new(User::new(2, "Blob Jr Jr"));
assert!(result.is_err());
assert_eq!(result, Err(Error::ElementWithSameIDFound(format!("2"))));
assert_eq!(
identified_vec.items(),
[User::blob(), User::blob_jr(), User::blob_sr()]
);
}

#[test]
fn append_other() {
let mut identified_vec = SUT::from_iter([1, 2, 3]);
Expand Down Expand Up @@ -372,6 +438,28 @@ fn update_or_append() {
assert_eq!(identified_vec.update_or_append(2), Some(2));
}

#[test]
fn try_update() {
let mut identified_vec = SUT::from_iter([1, 2, 3]);
assert_eq!(
identified_vec.try_update(4),
Err(Error::ExpectedElementNotPresent(format!("4")))
);
assert_eq!(identified_vec.items(), [1, 2, 3]);

let mut identified_vec: Users = IdentifiedVecOf::new();
identified_vec.append(User::blob());
identified_vec.append(User::blob_jr());
identified_vec.append(User::blob_sr());
let result = identified_vec.try_update(User::new(2, "Blob Jr Sr"));
assert!(result.is_ok());
assert_eq!(result, Ok(User::blob_jr()));
assert_eq!(
identified_vec.items(),
[User::blob(), User::new(2, "Blob Jr Sr"), User::blob_sr()]
);
}

#[test]
fn update_or_insert() {
let mut identified_vec = SUT::from_iter([1, 2, 3]);
Expand Down

0 comments on commit 7caf3e2

Please sign in to comment.