From 3dd010c7dda63f5e161e5cf07e51c4edc8f6f74f Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 15 Dec 2023 13:01:00 +0100 Subject: [PATCH] WIP --- identified_vec/src/is_identifiable_vec.rs | 84 ++++++++++----------- identified_vec/src/lib.rs | 4 + identified_vec/src/vec.rs | 92 +++++++++++------------ tests/tests.rs | 22 +++++- 4 files changed, 105 insertions(+), 97 deletions(-) diff --git a/identified_vec/src/is_identifiable_vec.rs b/identified_vec/src/is_identifiable_vec.rs index a6871a2..6ee0fff 100644 --- a/identified_vec/src/is_identifiable_vec.rs +++ b/identified_vec/src/is_identifiable_vec.rs @@ -2,13 +2,13 @@ use crate::conflict_resolution_choice::ConflictResolutionChoice; use std::fmt::Debug; use std::hash::Hash; -pub trait IsIdentifiableVec: Sized { - type Element; - type ID: Eq + Hash + Clone + Debug; - +pub trait IsIdentifiableVec: Sized +where + ID: Eq + Hash + Clone + Debug, +{ /// Constructs a new, empty `IdentifiedVec` with the specified /// `id_of_element` closure - fn new_identifying_element(id_of_element: fn(&Self::Element) -> Self::ID) -> Self; + fn new_identifying_element(id_of_element: fn(&Element) -> ID) -> Self; /// Creates a new `identified_vec` from the elements in the given sequence, using a combining closure to /// determine the element for any elements with duplicate identity. @@ -24,28 +24,26 @@ pub trait IsIdentifiableVec: Sized { /// - id_of_element: The function which extracts the identifier for an element, /// - combine: Closure trying to combine elements `(index, first, last)` with duplicate ids, returning which element to use, by use of ConflictResolutionChoice (`ChooseFirst` or `ChooseLast`), or `Err` if you prefer. /// - Returns: A new `identified_vec` initialized with the unique elements of `elements`. - /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `Self::ID` + /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `ID` /// implements high-quality hashing. fn try_from_iter_select_unique_ids_with( elements: It, - id_of_element: fn(&Self::Element) -> Self::ID, - combine: fn( - (usize, &Self::Element, &Self::Element), - ) -> Result, + id_of_element: fn(&Element) -> ID, + combine: fn((usize, &Element, &Element)) -> Result, ) -> Result where - It: IntoIterator; + It: IntoIterator; fn from_iter_select_unique_ids_with( elements: It, - id_of_element: fn(&Self::Element) -> Self::ID, - combine: fn((usize, &Self::Element, &Self::Element)) -> ConflictResolutionChoice, + id_of_element: fn(&Element) -> ID, + combine: fn((usize, &Element, &Element)) -> ConflictResolutionChoice, ) -> Self where - It: IntoIterator; + It: IntoIterator; - /// A read-only collection view for the ids contained in this `identified_vec`, as an `&Vec`. - fn ids(&self) -> &Vec; + ///The ids contained in this `identified_vec`, as an `Vec` (cloned) + fn ids(&self) -> Vec; /// Returns the number of elements in the `identified_vec`, also referred to as its 'length'. fn len(&self) -> usize; @@ -72,7 +70,7 @@ pub trait IsIdentifiableVec: Sized { /// /// impl Identifiable for User { /// type ID = &'static str; - /// fn id(&self) -> Self::ID { + /// fn id(&self) -> ID { /// self.id /// } /// } @@ -87,30 +85,30 @@ pub trait IsIdentifiableVec: Sized { /// - Parameter id: The id to find in the `identified_vec`. /// - Returns: The index for the element identified by `id` if found in the `identified_vec`; otherwise, /// `None`. - /// - Complexity: Expected to be O(1) on average, if `Self::ID` implements high-quality hashing. - fn index_of_id(&self, id: &Self::ID) -> Option; + /// - Complexity: Expected to be O(1) on average, if `ID` implements high-quality hashing. + fn index_of_id(&self, id: &ID) -> Option; /// Returns a mutable reference to the element identified by `id` if any, else None. /// /// - Parameter id: The id to find in the `identified_vec`. /// - Returns: The mutable reference to the element identified by `id` if found in the `identified_vec`; otherwise, /// `None`. - /// - Complexity: Expected to be O(1) on average, if `Self::ID` implements high-quality hashing. - fn get_mut(&mut self, id: &Self::ID) -> Option<&mut Self::Element>; + /// - Complexity: Expected to be O(1) on average, if `ID` implements high-quality hashing. + fn get_mut(&mut self, id: &ID) -> Option<&mut Element>; - fn elements(&self) -> Vec<&Self::Element>; + fn elements(&self) -> Vec<&Element>; /// Returns `true` if the `identified_vec` contains the `element.` - fn contains(&self, element: &Self::Element) -> bool; + fn contains(&self, element: &Element) -> bool; /// Returns `true if the `identified_vec` contains an element for the specified `id` - fn contains_id(&self, id: &Self::ID) -> bool; + fn contains_id(&self, id: &ID) -> bool; /// Returns a reference to the element corresponding to the `id`, if found, else `None`. - fn get(&self, id: &Self::ID) -> Option<&Self::Element>; + fn get(&self, id: &ID) -> Option<&Element>; /// Returns a reference to the element at index if found, else `None`. - fn get_at_index(&self, index: usize) -> Option<&Self::Element>; + fn get_at_index(&self, index: usize) -> Option<&Element>; /// Append a new member to the end of the `identified_vec`, if the `identified_vec` doesn't already contain it. /// @@ -119,18 +117,18 @@ pub trait IsIdentifiableVec: Sized { /// the operation added a new element, and `index` is the index of `item` in the resulting /// `identified_vec`. /// - Complexity: The operation is expected to perform O(1) copy, hash, and compare operations on - /// the `Self::ID` type, if it implements high-quality hashing. - fn append(&mut self, element: Self::Element) -> (bool, usize); + /// the `ID` type, if it implements high-quality hashing. + fn append(&mut self, element: Element) -> (bool, usize); /// Append the contents of an iterator to the end of the set, excluding elements that are already /// members. /// /// - Parameter elements: A finite sequence of elements to append. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::Element` type, if it implements high-quality hashing. + /// operations on the `Element` type, if it implements high-quality hashing. fn append_other(&mut self, other: It) where - It: IntoIterator; + It: IntoIterator; /// Adds the given element to the `identified_vec` unconditionally, either appending it to the `identified_vec``, or /// replacing an existing value if it's already present. @@ -139,8 +137,8 @@ pub trait IsIdentifiableVec: Sized { /// - Returns: The original element that was replaced by this operation, or `None` if the value was /// appended to the end of the collection. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::ID` type, if it implements high-quality hashing. - fn update_or_append(&mut self, element: Self::Element) -> Option; + /// operations on the `ID` type, if it implements high-quality hashing. + fn update_or_append(&mut self, element: Element) -> Option; /// Replace the member at the given index with a new value of the same identity. /// @@ -148,7 +146,7 @@ pub trait IsIdentifiableVec: Sized { /// the identity of the original value. /// - Parameter index: The index of the element to be replaced. /// - Returns: The original element that was replaced. - fn update_at(&mut self, element: Self::Element, index: usize) -> Self::Element; + fn update_at(&mut self, element: Element, index: usize) -> Element; /// Insert a new member to this identified_vec at the specified index, if the identified_vec doesn't already contain /// it. @@ -160,9 +158,9 @@ pub trait IsIdentifiableVec: Sized { /// requested. /// /// - Complexity: The operation is expected to perform amortized O(`self.count`) copy, hash, and - /// compare operations on the `Self::ID` type, if it implements high-quality hashing. (Insertions need + /// compare operations on the `ID` type, if it implements high-quality hashing. (Insertions need /// to make room in the storage identified_vec to add the inserted element.) - fn insert(&mut self, element: Self::Element, at: usize) -> (bool, usize); + fn insert(&mut self, element: Element, at: usize) -> (bool, usize); /// Adds the given element into the set unconditionally, either inserting it at the specified /// index, or replacing an existing value if it's already present. @@ -173,12 +171,8 @@ pub trait IsIdentifiableVec: Sized { /// - Returns: The original element that was replaced by this operation, or `None` if the value was /// newly inserted into the collection. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::ID` type, if it implements high-quality hashing. - fn update_or_insert( - &mut self, - element: Self::Element, - index: usize, - ) -> (Option, usize); + /// operations on the `ID` type, if it implements high-quality hashing. + fn update_or_insert(&mut self, element: Element, index: usize) -> (Option, usize); ///////////// // Remove // @@ -203,7 +197,7 @@ pub trait IsIdentifiableVec: Sized { /// /// impl Identifiable for User { /// type ID = &'static str; - /// fn id(&self) -> Self::ID { + /// fn id(&self) -> ID { /// self.id /// } /// } @@ -220,7 +214,7 @@ pub trait IsIdentifiableVec: Sized { /// - Parameter id: The id of the element to be removed from the `identified_vec`. /// - Returns: The element that was removed, or `None` if the element was not present in the array. /// - Complexity: O(`count`) - fn remove_by_id(&mut self, id: &Self::ID) -> Option; + fn remove_by_id(&mut self, id: &ID) -> Option; /// Removes the given element from the `identified_vec`. /// @@ -231,7 +225,7 @@ pub trait IsIdentifiableVec: Sized { /// - Parameter element: The element to remove. /// - Returns: The value that was removed, or `None` if the element was not present in the `identified_vec`. /// - Complexity: O(`count`) - fn remove(&mut self, element: &Self::Element) -> Option; + fn remove(&mut self, element: &Element) -> Option; /// Removes and returns the element at the specified position. /// @@ -242,7 +236,7 @@ pub trait IsIdentifiableVec: Sized { /// - Precondition: `index` must be a valid index of the collection that is not equal to the /// collection's end index. /// - Complexity: O(`count`) - fn remove_at(&mut self, index: usize) -> Self::Element; + fn remove_at(&mut self, index: usize) -> Element; /// Removes all the elements at the specified `offsets` from the `identified_vec`. /// diff --git a/identified_vec/src/lib.rs b/identified_vec/src/lib.rs index b24beb0..5fa5140 100644 --- a/identified_vec/src/lib.rs +++ b/identified_vec/src/lib.rs @@ -132,6 +132,8 @@ mod conflict_resolution_choice; 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; @@ -151,6 +153,8 @@ pub mod identified_vec_of { //! skip the `id_of_element: fn(&Element) -> ID` closure when //! initializing a new identified vec. pub use crate::identifiable_trait::*; + pub use crate::is_identifiable_vec_of::*; + pub use crate::is_identified_vec_via::*; pub use crate::vec_of::*; #[cfg(feature = "id_prim")] diff --git a/identified_vec/src/vec.rs b/identified_vec/src/vec.rs index dbc3391..af6a604 100644 --- a/identified_vec/src/vec.rs +++ b/identified_vec/src/vec.rs @@ -46,7 +46,7 @@ use crate::is_identifiable_vec::IsIdentifiableVec; /// /// impl Identifiable for User { /// type ID = &'static str; -/// fn id(&self) -> Self::ID { +/// fn id(&self) -> I { /// self.id /// } /// } @@ -76,7 +76,7 @@ use crate::is_identifiable_vec::IsIdentifiableVec; /// .collect::>() /// ); /// -/// // Self::Element with same Self::ID is not appended: +/// // E with same I is not appended: /// users.append(User::new("u_42", "Tom Mervolo Dolder")); /// assert_eq!( /// users.elements(), @@ -89,7 +89,7 @@ use crate::is_identifiable_vec::IsIdentifiableVec; /// .collect::>() /// ); /// -/// // Self::Element with same Self::ID replaces existing if an `update_*` method is used: +/// // E with same I replaces existing if an `update_*` method is used: /// // e.g. `update_or_insert`: /// users.update_or_insert(User::new("u_42", "Tom Mervolo Dolder"), 0); /// assert_eq!( @@ -148,7 +148,7 @@ use crate::is_identifiable_vec::IsIdentifiableVec; /// # Performance /// /// Like the standard `HashMap` type, the performance of hashing operations in -/// `IdentifiedVec` is highly sensitive to the quality of hashing implemented by the `Self::ID` +/// `IdentifiedVec` is highly sensitive to the quality of hashing implemented by the `I` /// type. Failing to correctly implement hashing can easily lead to unacceptable performance, with /// the severity of the effect increasing with the size of the underlying hash table. /// @@ -157,7 +157,7 @@ use crate::is_identifiable_vec::IsIdentifiableVec; /// ensure hashed collection types exhibit their target performance, it is important to ensure that /// such collisions cannot be induced merely by adding a particular list of members to the set. /// -/// When `Self::ID` implements `Hash` correctly, testing for membership in an ordered set is expected +/// When `I` implements `Hash` correctly, testing for membership in an ordered set is expected /// to take O(1) equality checks on average. Hash collisions can still occur organically, so the /// worst-case lookup performance is technically still O(*n*) (where *n* is the size of the set); /// however, long lookup chains are unlikely to occur in practice. @@ -178,11 +178,11 @@ where /// The storage of elements. pub(crate) elements: HashMap, - /// Function which extracts the Self::ID of an Self::Element. + /// Function which extracts the I of an E. pub(crate) _id_of_element: fn(&E) -> I, } -impl IsIdentifiableVec for IdentifiedVec +impl IsIdentifiableVec for IdentifiedVec where I: Eq + Hash + Clone + Debug, { @@ -190,9 +190,6 @@ where // Constructors // //////////////////// - type ID = I; - type Element = E; - /// Constructs a new, empty `IdentifiedVec` with the specified /// `id_of_element` closure #[inline] @@ -218,22 +215,20 @@ where /// - id_of_element: The function which extracts the identifier for an element, /// - combine: Closure trying to combine elements `(index, first, last)` with duplicate ids, returning which element to use, by use of ConflictResolutionChoice (`ChooseFirst` or `ChooseLast`), or `Err` if you prefer. /// - Returns: A new `identified_vec` initialized with the unique elements of `elements`. - /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `Self::ID` + /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `I` /// implements high-quality hashing. #[cfg(not(tarpaulin_include))] // false negative #[inline] fn try_from_iter_select_unique_ids_with( elements: It, - id_of_element: fn(&Self::Element) -> Self::ID, - combine: fn( - (usize, &Self::Element, &Self::Element), - ) -> Result, + id_of_element: fn(&E) -> I, + combine: fn((usize, &E, &E)) -> Result, ) -> Result where - It: IntoIterator, + It: IntoIterator, { - let mut _order = Vec::::new(); - let mut _elements = HashMap::::new(); + let mut _order = Vec::::new(); + let mut _elements = HashMap::::new(); for element in elements.into_iter() { let id = id_of_element(&element); @@ -278,20 +273,20 @@ where /// - id_of_element: The function which extracts the identifier for an element, /// - combine: Closure used combine elements `(index, first, last)` with duplicate ids, returning which element to use, by use of ConflictResolutionChoice (`ChooseFirst` or `ChooseLast`) /// - Returns: A new `identified_vec` initialized with the unique elements of `elements`. - /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `Self::ID` + /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `I` /// implements high-quality hashing. #[cfg(not(tarpaulin_include))] // false negative #[inline] fn from_iter_select_unique_ids_with( elements: It, - id_of_element: fn(&Self::Element) -> Self::ID, - combine: fn((usize, &Self::Element, &Self::Element)) -> ConflictResolutionChoice, + id_of_element: fn(&E) -> I, + combine: fn((usize, &E, &E)) -> ConflictResolutionChoice, ) -> Self where - It: IntoIterator, + It: IntoIterator, { - let mut _order = Vec::::new(); - let mut _elements = HashMap::::new(); + let mut _order = Vec::::new(); + let mut _elements = HashMap::::new(); for element in elements.into_iter() { let id = id_of_element(&element); @@ -319,12 +314,12 @@ where // Public Get // //////////////////// - /// A read-only collection view for the ids contained in this `identified_vec`, as an `&Vec`. + /// A read-only collection view for the ids contained in this `identified_vec`, as an `&Vec`. /// /// - Complexity: O(1) #[inline] - fn ids(&self) -> &Vec { - &self.order + fn ids(&self) -> Vec { + self.order.clone() } /// Returns the number of elements in the `identified_vec`, also referred to as its 'length'. @@ -358,7 +353,7 @@ where /// /// impl Identifiable for User { /// type ID = &'static str; - /// fn id(&self) -> Self::ID { + /// fn id(&self) -> I { /// self.id /// } /// } @@ -373,9 +368,9 @@ where /// - Parameter id: The id to find in the `identified_vec`. /// - Returns: The index for the element identified by `id` if found in the `identified_vec`; otherwise, /// `None`. - /// - Complexity: Expected to be O(1) on average, if `Self::ID` implements high-quality hashing. + /// - Complexity: Expected to be O(1) on average, if `I` implements high-quality hashing. #[inline] - fn index_of_id(&self, id: &Self::ID) -> Option { + fn index_of_id(&self, id: &I) -> Option { self.order.iter().position(|i| i == id) } @@ -384,9 +379,9 @@ where /// - Parameter id: The id to find in the `identified_vec`. /// - Returns: The mutable reference to the element identified by `id` if found in the `identified_vec`; otherwise, /// `None`. - /// - Complexity: Expected to be O(1) on average, if `Self::ID` implements high-quality hashing. + /// - Complexity: Expected to be O(1) on average, if `I` implements high-quality hashing. #[inline] - fn get_mut(&mut self, id: &Self::ID) -> Option<&mut Self::Element> { + fn get_mut(&mut self, id: &I) -> Option<&mut E> { self.elements.get_mut(id) } @@ -398,35 +393,35 @@ where /// /// N.B. that this method is not constant time. /// - /// If `Self::Element` implements `Clone` you can use `self.items()` which returns a `Vec`, of cloned elements. + /// If `E` implements `Clone` you can use `self.items()` which returns a `Vec`, of cloned elements. /// /// - Complexity: O(n) #[inline] - fn elements(&self) -> Vec<&Self::Element> { + fn elements(&self) -> Vec<&E> { self.iter().collect() } /// Returns `true` if the `identified_vec` contains the `element.` #[inline] - fn contains(&self, element: &Self::Element) -> bool { + fn contains(&self, element: &E) -> bool { self.elements.contains_key(&self.id(&element)) } /// Returns `true if the `identified_vec` contains an element for the specified `id` #[inline] - fn contains_id(&self, id: &Self::ID) -> bool { + fn contains_id(&self, id: &I) -> bool { self.elements.contains_key(id) } /// Returns a reference to the element corresponding to the `id`, if found, else `None`. #[inline] - fn get(&self, id: &Self::ID) -> Option<&Self::Element> { + fn get(&self, id: &I) -> Option<&E> { self.elements.get(id) } /// Returns a reference to the element at index if found, else `None`. #[inline] - fn get_at_index(&self, index: usize) -> Option<&Self::Element> { + fn get_at_index(&self, index: usize) -> Option<&E> { self.order.get(index).and_then(|id| self.get(id)) } @@ -437,7 +432,7 @@ where /// the operation added a new element, and `index` is the index of `item` in the resulting /// `identified_vec`. /// - Complexity: The operation is expected to perform O(1) copy, hash, and compare operations on - /// the `Self::ID` type, if it implements high-quality hashing. + /// the `I` type, if it implements high-quality hashing. #[inline] fn append(&mut self, element: E) -> (bool, usize) { self.insert(element, self.end_index()) @@ -448,7 +443,7 @@ where /// /// - Parameter elements: A finite sequence of elements to append. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::Element` type, if it implements high-quality hashing. + /// operations on the `E` type, if it implements high-quality hashing. #[inline] fn append_other(&mut self, other: It) where @@ -464,7 +459,7 @@ where /// - Returns: The original element that was replaced by this operation, or `None` if the value was /// appended to the end of the collection. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::ID` type, if it implements high-quality hashing. + /// operations on the `I` type, if it implements high-quality hashing. #[inline] fn update_or_append(&mut self, element: E) -> Option { let id = self.id(&element); @@ -505,7 +500,7 @@ where /// requested. /// /// - Complexity: The operation is expected to perform amortized O(`self.count`) copy, hash, and - /// compare operations on the `Self::ID` type, if it implements high-quality hashing. (Insertions need + /// compare operations on the `I` type, if it implements high-quality hashing. (Insertions need /// to make room in the storage identified_vec to add the inserted element.) #[cfg(not(tarpaulin_include))] // false negative #[inline] @@ -527,7 +522,7 @@ where /// - Returns: The original element that was replaced by this operation, or `None` if the value was /// newly inserted into the collection. /// - Complexity: The operation is expected to perform amortized O(1) copy, hash, and compare - /// operations on the `Self::ID` type, if it implements high-quality hashing. + /// operations on the `I` type, if it implements high-quality hashing. #[inline] fn update_or_insert(&mut self, element: E, index: usize) -> (Option, usize) { let id = self.id(&element); @@ -556,7 +551,7 @@ where /// /// impl Identifiable for User { /// type ID = &'static str; - /// fn id(&self) -> Self::ID { + /// fn id(&self) -> I { /// self.id /// } /// } @@ -617,10 +612,7 @@ where .order .get(index) .expect("Precondition failure, index out of bounds"); - let removed = self - .elements - .remove(id) - .expect("Self::Element of existing id"); + let removed = self.elements.remove(id).expect("E of existing id"); self.order.remove(index); return removed; } @@ -796,13 +788,13 @@ where self.len() } - /// Returns the Self::ID of an Self::Element + /// Returns the I of an E #[inline] fn id(&self, of: &E) -> I { (self._id_of_element)(of) } - /// Inserting Self::ID at an index, returning if it did, if not, the index of the existing. + /// Inserting I at an index, returning if it did, if not, the index of the existing. #[cfg(not(tarpaulin_include))] // false negative #[inline] fn _insert_id_at(&mut self, id: I, index: usize) -> (bool, usize) { diff --git a/tests/tests.rs b/tests/tests.rs index e51b40a..294471a 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -2,7 +2,8 @@ use std::{cell::RefCell, collections::HashSet, fmt::Debug, ops::Deref}; use identified_vec::{ ConflictResolutionChoice, Identifiable, IdentifiedVec, IdentifiedVecOf, - IdentifiedVecOfSerdeFailure, IsIdentifiableVec, + IdentifiedVecOfSerdeFailure, IsIdentifiableVec, IsIdentifiableVecOf, IsIdentifiableVecOfVia, + ViaMarker, }; use identified_vec_macros::newtype_identified_vec; @@ -536,7 +537,24 @@ fn hash() { ) } -// Test macro +// Test IsIdentifiedVecVia +struct CollectionOfUsersVia(IdentifiedVecOf); +impl ViaMarker for CollectionOfUsersVia {} +impl IsIdentifiableVecOf for CollectionOfUsersVia {} +impl IsIdentifiableVecOfVia for CollectionOfUsersVia { + fn via(&self) -> &mut IdentifiedVecOf { + todo!() + } + fn from_identified_vec_of(identified_vec_of: IdentifiedVecOf) -> Self { + Self(identified_vec_of) + } +} + +// impl IsIdentifiableVecOfVia for CollectionOfUsersVia { +// fn via(&self) -> &mut IdentifiedVecOf { +// todo!() +// } +// } #[test] fn test_macro() {