Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajjon committed Dec 15, 2023
2 parents bdff691 + 7caf3e2 commit 88744c3
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 13 deletions.
16 changes: 16 additions & 0 deletions identified_vec/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#[cfg(feature = "serde")]
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
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),
}
13 changes: 13 additions & 0 deletions identified_vec/src/is_identifiable_vec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::conflict_resolution_choice::ConflictResolutionChoice;
use crate::Error;
use std::fmt::Debug;
use std::hash::Hash;

Expand Down Expand Up @@ -140,6 +141,10 @@ where
/// - Returns: The original element that was replaced.
fn update_at(&mut self, element: Element, index: usize) -> Element;

fn update_with<F>(&mut self, id: &ID, mutate: F) -> bool
where
F: Fn(&mut Element);

/// Insert a new member to this identified_vec at the specified index, if the identified_vec doesn't already contain
/// it.
///
Expand All @@ -166,6 +171,14 @@ where
/// operations on the `ID` type, if it implements high-quality hashing.
fn update_or_insert(&mut self, element: Element, index: usize) -> (Option<Element>, usize);

/// 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.
fn try_update(&mut self, element: Element) -> Result<Element, Error>;

/////////////
// Remove //
/////////////
Expand Down
39 changes: 37 additions & 2 deletions identified_vec/src/is_identified_vec_via.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::conflict_resolution_choice::ConflictResolutionChoice;
use crate::{Identifiable, IdentifiedVecOf, IsIdentifiableVec, IsIdentifiableVecOf};
use crate::{Error, Identifiable, IdentifiedVecOf, IsIdentifiableVec, IsIdentifiableVecOf};

/// https://stackoverflow.com/a/66537661/1311272
pub trait ViaMarker {}
Expand All @@ -19,10 +19,12 @@ where
Element: Identifiable,
U: IsIdentifiableVecOfVia<Element>,
{
#[inline]
fn new() -> Self {
Self::from_identified_vec_of(IdentifiedVecOf::new())
}

#[inline]
fn from_iter<It>(unique_elements: It) -> Self
where
It: IntoIterator<Item = Element>,
Expand All @@ -37,12 +39,14 @@ where
Element: Identifiable,
U: IsIdentifiableVecOfVia<Element>,
{
#[inline]
fn new_identifying_element(
id_of_element: fn(&Element) -> <Element as Identifiable>::ID,
) -> Self {
Self::from_identified_vec_of(IdentifiedVecOf::new_identifying_element(id_of_element))
}

#[inline]
fn try_from_iter_select_unique_ids_with<Er, It>(
elements: It,
id_of_element: fn(&Element) -> <Element as Identifiable>::ID,
Expand All @@ -55,6 +59,7 @@ where
.map(|via| Self::from_identified_vec_of(via))
}

#[inline]
fn from_iter_select_unique_ids_with<It>(
elements: It,
id_of_element: fn(&Element) -> <Element as Identifiable>::ID,
Expand All @@ -70,81 +75,111 @@ where
))
}

#[inline]
fn ids(&self) -> Vec<<Element as Identifiable>::ID> {
self.via().ids()
}

#[inline]
fn len(&self) -> usize {
self.via().len()
}

#[inline]
fn index_of_id(&self, id: &<Element as Identifiable>::ID) -> Option<usize> {
self.via().index_of_id(id)
}

#[inline]
fn elements(&self) -> Vec<&Element> {
self.via().elements()
}

#[inline]
fn contains(&self, element: &Element) -> bool {
self.via().contains(element)
}

#[inline]
fn contains_id(&self, id: &<Element as Identifiable>::ID) -> bool {
self.via().contains_id(id)
}

#[inline]
fn get(&self, id: &<Element as Identifiable>::ID) -> Option<&Element> {
self.via().get(id)
}

#[inline]
fn get_at_index(&self, index: usize) -> Option<&Element> {
self.via().get_at_index(index)
}

#[inline]
fn append(&mut self, element: Element) -> (bool, usize) {
self.via_mut().append(element)
}

#[inline]
fn append_other<It>(&mut self, other: It)
where
It: IntoIterator<Item = Element>,
{
self.via_mut().append_other(other)
}

#[inline]
fn update_or_append(&mut self, element: Element) -> Option<Element> {
self.via_mut().update_or_append(element)
}

#[inline]
fn update_at(&mut self, element: Element, index: usize) -> Element {
self.via_mut().update_at(element, index)
}

#[inline]
fn insert(&mut self, element: Element, at: usize) -> (bool, usize) {
self.via_mut().insert(element, at)
}

#[inline]
fn update_or_insert(&mut self, element: Element, index: usize) -> (Option<Element>, usize) {
self.via_mut().update_or_insert(element, index)
}

#[inline]
fn try_update(&mut self, element: Element) -> Result<Element, Error> {
self.via_mut().try_update(element)
}

#[inline]
fn update_with<F>(&mut self, id: &<Element as Identifiable>::ID, mutate: F) -> bool
where
F: Fn(&mut Element),
{
self.via_mut().update_with(id, mutate)
}

/////////////
// Remove //
/////////////

#[inline]
fn remove_by_id(&mut self, id: &<Element as Identifiable>::ID) -> Option<Element> {
self.via_mut().remove_by_id(id)
}

#[inline]
fn remove(&mut self, element: &Element) -> Option<Element> {
self.via_mut().remove(element)
}

#[inline]
fn remove_at(&mut self, index: usize) -> Element {
self.via_mut().remove_at(index)
}

#[inline]
fn remove_at_offsets<It>(&mut self, offsets: It)
where
It: IntoIterator<Item = usize>,
Expand Down
6 changes: 3 additions & 3 deletions identified_vec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,14 @@
//! let numbers = IdentifiedVec::<u32, u32>::new_identifying_element(|e| *e);
//! ```
mod Is_identifiable_vec;
mod conflict_resolution_choice;
mod errors;
mod identifiable_trait;
mod is_identifiable_vec;
mod is_identifiable_vec_of;
mod is_identified_vec_via;
mod primitives_identifiable;
mod serde_error;
mod vec;
mod vec_of;

Expand All @@ -147,8 +148,7 @@ pub mod identified_vec_of {
#[cfg(feature = "id_prim")]
pub use crate::primitives_identifiable::*;

#[cfg(feature = "serde")]
pub use crate::serde_error::*;
pub use crate::errors::*;
}

pub use crate::identified_vec::*;
Expand Down
6 changes: 0 additions & 6 deletions identified_vec/src/serde_error.rs

This file was deleted.

89 changes: 89 additions & 0 deletions identified_vec/src/vec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::conflict_resolution_choice::ConflictResolutionChoice;
use crate::errors::Error;
use std::collections::HashMap;
use std::fmt::{Debug, Display};
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -466,6 +467,41 @@ where
.expect("Replaced old value");
}

/// Returns `false` if no element of `id` was found, otherwise if found, this
/// existing element gets updated by `mutate` closure and this function returns
/// `true`.
#[inline]
fn update_with<F>(&mut self, id: &I, mutate: F) -> bool
where
F: Fn(&mut E),
{
if !self.contains_id(id) {
return false;
}
let mut existing = self.elements.remove(id).expect("Element for existing id");
mutate(&mut existing);
self.elements.insert(id.clone(), existing);
true
}

/// 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]
fn try_update(&mut self, element: E) -> Result<E, 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 Expand Up @@ -840,3 +876,56 @@ where
format!("order: {:?}\nelements: {:?}", self.order, self.elements)
}
}

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` will 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))
}
}
2 changes: 1 addition & 1 deletion identified_vec/src/vec_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::HashMap;
use std::fmt::Debug;

#[cfg(feature = "serde")]
use crate::serde_error::IdentifiedVecOfSerdeFailure;
use crate::errors::IdentifiedVecOfSerdeFailure;
use crate::IsIdentifiableVecOf;
use crate::{
conflict_resolution_choice::ConflictResolutionChoice, is_identifiable_vec::IsIdentifiableVec,
Expand Down
Loading

0 comments on commit 88744c3

Please sign in to comment.