From cc004c83a05d0ecfef3f91dcedae77a8f71542ac Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Wed, 13 Dec 2023 21:40:16 +0100 Subject: [PATCH] WIP --- Cargo.lock | 22 +- Cargo.toml | 28 +- src/identifiable_trait.rs | 18 - src/lib.rs | 165 ----- src/primitives_identifiable.rs | 26 - src/serde_error.rs | 6 - src/vec.rs | 1133 -------------------------------- src/vec_of.rs | 154 ----- 8 files changed, 19 insertions(+), 1533 deletions(-) delete mode 100644 src/identifiable_trait.rs delete mode 100644 src/lib.rs delete mode 100644 src/primitives_identifiable.rs delete mode 100644 src/serde_error.rs delete mode 100644 src/vec.rs delete mode 100644 src/vec_of.rs diff --git a/Cargo.lock b/Cargo.lock index 12f4005..0a90669 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,17 +31,27 @@ dependencies = [ "thiserror", ] +[[package]] +name = "identified_vec_macros" +version = "0.1.0" +dependencies = [ + "identified_vec", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "maplit" @@ -105,9 +115,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index cfd57c2..7a5579a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,27 +1,5 @@ -[package] -name = "identified_vec" -version = "0.1.4" -edition = "2021" -authors = ["Alexander Cyon "] -description = "Like HashSet but retaining INSERTION order and without `Hash` requirement on the Element type." -license = "MIT" -readme = "README.md" -repository = "https://github.com/Sajjon/identified_vec" -keywords = ["identifiable", "vec", "orderset", "set", "hashset"] -categories = ["data-structures"] +[workspace] -[features] -serde = ["dep:serde"] -id_prim = [] -is_id_vec_of = [] +resolver = "2" -[dependencies] -serde = { version = "1.0.193", optional = true } -thiserror = "1.0.50" - -[dev-dependencies] -identified_vec = { path = ".", features = ["id_prim", "serde"] } -serde = "1.0.193" -serde_json = "1.0.108" -rand = "0.8.5" -maplit = "1.0.2" +members = ["identified_vec", "identified_vec_macros"] diff --git a/src/identifiable_trait.rs b/src/identifiable_trait.rs deleted file mode 100644 index db68826..0000000 --- a/src/identifiable_trait.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::fmt::Debug; -use std::hash::Hash; - -/// The `Identifiable` trait allows you to use the -/// `IdentifiedVecOf instead of the more verbose -/// `IdentifiedVec` but also allows you to -/// skip the `id_of_element: fn(&Element) -> ID` closure when -/// initializing a new identified vec. -pub trait Identifiable { - /// The type that your `Element` will use as its globally unique and stable ID, - /// must impl `Hash` since it is used as a key in `IdentifiedVecOf`'s internal - /// `HashMap`. Must impl `Clone` since we need to be able to clone it as a key - type ID: Eq + Hash + Clone + Debug; - - /// Return `Element`'s globally unique and stable ID, used to uniquely identify - /// the `Element` in the `IdentifiedVecOf` collection of elements. - fn id(&self) -> Self::ID; -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 4dfc4d1..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! A collection of unique identifiable elements which retains **insertion** order, inspired by [Pointfree's Swift Identified Collections](https://github.com/pointfreeco/swift-identified-collections). -//! -//! Similar to the standard `Vec`, the `IdentifiedVec` maintain their elements in a particular user-specified order. However, unlike `Vec`, the `IdentifiedVec` introduce the ability to uniquely identify elements, using a hash table to ensure that no two elements have the same identity, and to efficiently look up elements corresponding to specific identifiers. -//! -//! `IdentifiedVec` is a useful alternative to `Vec` when you need to be able to efficiently access unique elements by a stable identifier. It is also a useful alternative to `BTreeSet`, where the `Ord` trait requirement may be too strict, an a useful alternative to `HashSet` where `Hash` trait requirement may be too strict. -//! -//! You can create an identified vec with any element type that implements the `Identifiable` trait. -//! -//! # Example -//! -//! ``` -//! extern crate identified_vec; -//! use identified_vec::{IsIdentifiableVec, IdentifiedVec, IdentifiedVecOf, Identifiable}; -//! use std::cell::RefCell; -//! -//! #[derive(Eq, PartialEq, Clone, Debug)] -//! struct User { -//! id: &'static str, -//! name: RefCell<&'static str>, -//! } -//! -//! impl User { -//! fn new(id: &'static str, name: &'static str) -> Self { -//! Self { -//! id, -//! name: RefCell::new(name), -//! } -//! } -//! fn name(&self) -> &'static str { -//! *self.name.borrow() -//! } -//! } -//! -//! impl Identifiable for User { -//! type ID = &'static str; -//! fn id(&self) -> Self::ID { -//! self.id -//! } -//! } -//! -//! let mut users = IdentifiedVecOf::::from_iter([ -//! User::new("u_42", "Satoshi Nakamoto"), -//! User::new("u_1337", "Leia Skywalker"), -//! ]); -//! -//! assert_eq!( -//! users.get(&"u_42").map(|u| u.name()), -//! Some("Satoshi Nakamoto") -//! ); -//! -//! assert_eq!( -//! users.get_at_index(1).map(|u| u.name()), -//! Some("Leia Skywalker") -//! ); -//! -//! users.append(User::new("u_237", "Alan Turing")); -//! assert_eq!( -//! users.elements(), -//! [ -//! User::new("u_42", "Satoshi Nakamoto"), -//! User::new("u_1337", "Leia Skywalker"), -//! User::new("u_237", "Alan Turing"), -//! ] -//! .iter() -//! .collect::>() -//! ); -//! -//! // Element with same ID is not appended: -//! users.append(User::new("u_42", "Tom Mervolo Dolder")); -//! assert_eq!( -//! users.elements(), -//! [ -//! User::new("u_42", "Satoshi Nakamoto"), -//! User::new("u_1337", "Leia Skywalker"), -//! User::new("u_237", "Alan Turing"), -//! ] -//! .iter() -//! .collect::>() -//! ); -//! -//! // Element with same ID 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!( -//! users.elements(), -//! [ -//! User::new("u_42", "Tom Mervolo Dolder"), -//! User::new("u_1337", "Leia Skywalker"), -//! User::new("u_237", "Alan Turing"), -//! ] -//! .iter() -//! .collect::>() -//! ); -//! -//! // or `update_or_append` -//! users.update_or_append(User::new("u_237", "Marie Curie")); -//! assert_eq!( -//! users.elements(), -//! [ -//! User::new("u_42", "Tom Mervolo Dolder"), -//! User::new("u_1337", "Leia Skywalker"), -//! User::new("u_237", "Marie Curie"), -//! ] -//! .iter() -//! .collect::>() -//! ); -//! -//! // or mutate with `get_mut(id)` -//! *users.get_mut(&"u_1337").unwrap().name.get_mut() = "Yoda"; -//! assert_eq!( -//! users.elements(), -//! [ -//! User::new("u_42", "Tom Mervolo Dolder"), -//! User::new("u_1337", "Yoda"), -//! User::new("u_237", "Marie Curie"), -//! ] -//! .iter() -//! .collect::>() -//! ); -//! ``` -//! -//! Or you can provide a closure that describes an element's identity: -//! -//! ``` -//! extern crate identified_vec; -//! use identified_vec::{IsIdentifiableVec, IdentifiedVec, IdentifiedVecOf, Identifiable}; -//! -//! // closure which plucks out an ID from an element. -//! let numbers = IdentifiedVec::::new_identifying_element(|e| *e); -//! ``` - -mod identifiable_trait; -mod is_id_vec_of; -mod primitives_identifiable; -mod serde_error; -mod vec; -mod vec_of; - -pub mod identified_vec { - //! A collection of unique identifiable elements which retains **insertion** order. - pub use crate::vec::*; -} - -pub mod identified_vec_of { - //! The `Identifiable` trait allows you to use the - //! `IdentifiedVecOf instead of the more verbose - //! `IdentifiedVec` but also allows you to - //! skip the `id_of_element: fn(&Element) -> ID` closure when - //! initializing a new identified vec. - pub use crate::identifiable_trait::*; - pub use crate::vec_of::*; - - #[cfg(feature = "id_prim")] - pub use crate::primitives_identifiable::*; - - #[cfg(feature = "serde")] - pub use crate::serde_error::*; - - #[cfg(feature = "is_id_vec_of")] - pub use crate::is_id_vec_of::*; -} - -pub use crate::identified_vec::*; -pub use crate::identified_vec_of::*; -pub use crate::vec::IsIdentifiableVec; diff --git a/src/primitives_identifiable.rs b/src/primitives_identifiable.rs deleted file mode 100644 index 1081c11..0000000 --- a/src/primitives_identifiable.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![cfg(feature = "id_prim")] - -use crate::identified_vec_of::Identifiable; - -macro_rules! impl_id { - ($primitive_type:ident) => { - impl Identifiable for $primitive_type { - type ID = $primitive_type; - fn id(&self) -> Self::ID { - *self - } - } - }; -} - -impl_id!(i8); -impl_id!(i16); -impl_id!(i32); -impl_id!(i64); -impl_id!(i128); -impl_id!(u8); -impl_id!(u16); -impl_id!(u32); -impl_id!(u64); -impl_id!(u128); -impl_id!(bool); diff --git a/src/serde_error.rs b/src/serde_error.rs deleted file mode 100644 index 5a25995..0000000 --- a/src/serde_error.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[cfg(feature = "serde")] -#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)] -pub enum IdentifiedVecOfSerdeFailure { - #[error("Duplicate element at offset {0}")] - DuplicateElementsAtIndex(usize), -} diff --git a/src/vec.rs b/src/vec.rs deleted file mode 100644 index 38c0808..0000000 --- a/src/vec.rs +++ /dev/null @@ -1,1133 +0,0 @@ -use std::collections::HashMap; -use std::fmt::{Debug, Display}; -use std::hash::{Hash, Hasher}; - -pub trait IsIdentifiableVec: Sized { - type Element; - type 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; - - /// 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. - /// - /// You use this initializer to create an `identified_vec` when you have an arbitrary sequence of elements - /// that may not have unique ids. This initializer calls the `combine` closure with the current - /// and new elements for any duplicate ids. Pass a closure as `combine` that returns the element - /// to use in the resulting `identified_vec`: The closure can choose between the two elements, combine them - /// to produce a new element, or even throw an error. - /// - /// - Parameters: - /// - elements: A sequence of elements to use for the new `identified_vec`. - /// - 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` - /// 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, - ) -> Result - where - 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, - ) -> Self - where - It: IntoIterator; - - /// A read-only collection view for the ids contained in this `identified_vec`, as an `&Vec`. - fn ids(&self) -> &Vec; - - /// Returns the number of elements in the `identified_vec`, also referred to as its 'length'. - fn len(&self) -> usize; - - /// Returns the index for the given id. - /// - /// If an element identified by the given id is found in the `identified_vec`, this method returns an index - /// into the array that corresponds to the element. - /// - /// ``` - /// extern crate identified_vec; - /// use identified_vec::{IsIdentifiableVec, IdentifiedVec, Identifiable, IdentifiedVecOf}; - /// - /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] - /// struct User { - /// id: &'static str, - /// } - /// - /// impl User { - /// fn new(id: &'static str) -> Self { - /// Self { id } - /// } - /// } - /// - /// impl Identifiable for User { - /// type ID = &'static str; - /// fn id(&self) -> Self::ID { - /// self.id - /// } - /// } - /// - /// let mut users = - /// IdentifiedVecOf::::from_iter([User::new("u_42"), User::new("u_1729")]); - /// - /// assert_eq!(users.index_of_id(&"u_1729"), Some(1)); - /// assert_eq!(users.index_of_id(&"u_1337"), None); - /// ``` - /// - /// - 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; - - /// 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>; - - fn elements(&self) -> Vec<&Self::Element>; - - /// Returns `true` if the `identified_vec` contains the `element.` - fn contains(&self, element: &Self::Element) -> bool; - - /// Returns `true if the `identified_vec` contains an element for the specified `id` - fn contains_id(&self, id: &Self::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>; - - /// Returns a reference to the element at index if found, else `None`. - fn get_at_index(&self, index: usize) -> Option<&Self::Element>; - - /// Append a new member to the end of the `identified_vec`, if the `identified_vec` doesn't already contain it. - /// - /// - Parameter item: The element to add to the `identified_vec`. - /// - Returns: 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`. - /// - 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); - - /// 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. - fn append_other(&mut self, other: It) - where - 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. - /// - /// - Parameter item: The value to append or replace. - /// - 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; - - /// Replace the member at the given index with a new value of the same identity. - /// - /// - Parameter item: The new value that should replace the original element. `item` must match - /// 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; - - /// Insert a new member to this identified_vec at the specified index, if the identified_vec doesn't already contain - /// it. - /// - /// - Parameter element: The element to insert. - /// - Returns: A pair `(inserted, index)`, where `inserted` is a Boolean value indicating whether - /// the operation added a new element, and `index` is the index of `element` in the resulting - /// identified_vec. If `inserted` is true, then the returned `index` may be different from the index - /// 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 - /// to make room in the storage identified_vec to add the inserted element.) - fn insert(&mut self, element: Self::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. - /// - /// - Parameter item: The value to append or replace. - /// - Parameter index: The index at which to insert the new member if `item` isn't already in the - /// set. - /// - 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); - - ///////////// - // Remove // - ///////////// - - /// Removes the element identified by the given id from the `identified_vec`. - /// - /// ``` - /// extern crate identified_vec; - /// use identified_vec::{IsIdentifiableVec, IdentifiedVec, Identifiable, IdentifiedVecOf}; - /// - /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] - /// struct User { - /// id: &'static str, - /// } - /// - /// impl User { - /// fn new(id: &'static str) -> Self { - /// Self { id } - /// } - /// } - /// - /// impl Identifiable for User { - /// type ID = &'static str; - /// fn id(&self) -> Self::ID { - /// self.id - /// } - /// } - /// - /// let mut users = - /// IdentifiedVecOf::::from_iter([User::new("u_42"), User::new("u_1729")]); - /// - /// assert_eq!(users.remove_by_id(&"u_1729"), Some(User::new("u_1729"))); - /// assert_eq!(users.elements(), [&User::new("u_42")]); - /// assert_eq!(users.remove_by_id(&"u_1337"), None); - /// assert_eq!(users.len(), 1); - /// ``` - /// - /// - 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; - - /// Removes the given element from the `identified_vec`. - /// - /// If the element is found in the `identified_vec`, this method returns the element. - /// - /// If the element isn't found in the `identified_vec`, `remove` returns `None`. - /// - /// - 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; - - /// Removes and returns the element at the specified position. - /// - /// All the elements following the specified position are moved to close the resulting gap. - /// - /// - Parameter index: The position of the element to remove. - /// - Returns: The removed element. - /// - 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; - - /// Removes all the elements at the specified `offsets` from the `identified_vec`. - /// - /// - Parameter offsets: The offsets of all elements to be removed. - /// - Complexity: O(*n*) where *n* is the length of the `identified_vec`. - fn remove_at_offsets(&mut self, offsets: It) - where - It: IntoIterator; -} - -/// Representation of a choice in a conflict resolution -/// where two elements with the same Self::ID exists, if `ChooseFirst`, -/// is specified the first/current/existing value will be used, but -/// if `ChooseLast` is specified then the new/last will be replace -/// the first/current/existing. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ConflictResolutionChoice { - ChooseFirst, - ChooseLast, -} - -/// An ordered collection of identifiable elements. -/// -/// Similar to the standard `Vec`, identified vecs maintain their elements in a particular -/// user-specified order, and they support efficient random access traversal of their members. -/// However, unlike `Vec`, identified vecs introduce the ability to uniquely identify elements, -/// using a hash table to ensure that no two elements have the same identity, and to efficiently -/// look up elements corresponding to specific identifiers. -/// -/// `IdentifiedVec` is a useful alternative to `Vec` when you need to be able to efficiently -/// access unique elements by a stable identifier. It is also a useful alternative to `BTreeSet`, -/// where the `Ord` requirement may be too strict, an a useful alternative to `HashSet` where -/// `Hash` requirement may be too strict. -/// -/// You can create an identified vec with any element type that implements the `Identifiable` -/// trait. -/// -/// ``` -/// extern crate identified_vec; -/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf, IsIdentifiableVec}; -/// use std::cell::RefCell; -/// -/// #[derive(Eq, PartialEq, Clone, Debug)] -/// struct User { -/// id: &'static str, -/// name: RefCell<&'static str>, -/// } -/// -/// impl User { -/// fn new(id: &'static str, name: &'static str) -> Self { -/// Self { -/// id, -/// name: RefCell::new(name), -/// } -/// } -/// fn name(&self) -> &'static str { -/// *self.name.borrow() -/// } -/// } -/// -/// impl Identifiable for User { -/// type ID = &'static str; -/// fn id(&self) -> Self::ID { -/// self.id -/// } -/// } -/// -/// let mut users = IdentifiedVecOf::::from_iter([ -/// User::new("u_42", "Satoshi Nakamoto"), -/// User::new("u_1337", "Leia Skywalker"), -/// ]); -/// -/// assert_eq!( -/// users.get(&"u_42").map(|u| u.name()), -/// Some("Satoshi Nakamoto") -/// ); -/// assert_eq!( -/// users.get_at_index(1).map(|u| u.name()), -/// Some("Leia Skywalker") -/// ); -/// users.append(User::new("u_237", "Alan Turing")); -/// assert_eq!( -/// users.elements(), -/// [ -/// User::new("u_42", "Satoshi Nakamoto"), -/// User::new("u_1337", "Leia Skywalker"), -/// User::new("u_237", "Alan Turing"), -/// ] -/// .iter() -/// .collect::>() -/// ); -/// -/// // Self::Element with same Self::ID is not appended: -/// users.append(User::new("u_42", "Tom Mervolo Dolder")); -/// assert_eq!( -/// users.elements(), -/// [ -/// User::new("u_42", "Satoshi Nakamoto"), -/// User::new("u_1337", "Leia Skywalker"), -/// User::new("u_237", "Alan Turing"), -/// ] -/// .iter() -/// .collect::>() -/// ); -/// -/// // Self::Element with same Self::ID 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!( -/// users.elements(), -/// [ -/// User::new("u_42", "Tom Mervolo Dolder"), -/// User::new("u_1337", "Leia Skywalker"), -/// User::new("u_237", "Alan Turing"), -/// ] -/// .iter() -/// .collect::>() -/// ); -/// -/// // or `update_or_append` -/// users.update_or_append(User::new("u_237", "Marie Curie")); -/// assert_eq!( -/// users.elements(), -/// [ -/// User::new("u_42", "Tom Mervolo Dolder"), -/// User::new("u_1337", "Leia Skywalker"), -/// User::new("u_237", "Marie Curie"), -/// ] -/// .iter() -/// .collect::>() -/// ); -/// -/// // or mutate with `get_mut(id)` -/// *users.get_mut(&"u_1337").unwrap().name.get_mut() = "Yoda"; -/// assert_eq!( -/// users.elements(), -/// [ -/// User::new("u_42", "Tom Mervolo Dolder"), -/// User::new("u_1337", "Yoda"), -/// User::new("u_237", "Marie Curie"), -/// ] -/// .iter() -/// .collect::>() -/// ); -/// ``` -/// -/// Or you can provide a closure that describes an element's identity: -/// -/// ``` -/// /// extern crate identified_vec; -/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf, IsIdentifiableVec}; -/// -/// let numbers = IdentifiedVec::::new_identifying_element(|e| *e); -/// ``` -/// -/// # Motivation -/// None of the std collections `BTreeSet` and `HashSet` retain insertion order, `Vec` retains -/// insertion order, however, it allows for duplicates. So if you want a collection of unique -/// elements (Set-like) that does retain insertion order, `IdentifiedVec` suits your needs. -/// Even better, the elements does not need to be to impl `Hash` nor `Ord``. -/// -/// # 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` -/// 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. -/// -/// In particular, if a certain set of elements all produce the same hash value, then hash table -/// lookups regress to searching an element in an unsorted array, i.e., a linear operation. To -/// 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 -/// 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. -/// -/// ## Implementation Details -/// -/// An identified vec consists of a Vec and a HashMap of id-element pairs. An element's id -/// should not be mutated in place, as it will drift from its associated dictionary key. Identified -/// bec is designed to avoid this invariant. Mutating an element's id will result in a runtime error. -#[derive(Debug, Clone)] -pub struct IdentifiedVec -where - I: Eq + Hash + Clone + Debug, -{ - /// The holder of the insertion order - pub(crate) order: Vec, - - /// The storage of elements. - pub(crate) elements: HashMap, - - /// Function which extracts the Self::ID of an Self::Element. - pub(crate) _id_of_element: fn(&E) -> I, -} - -impl IsIdentifiableVec for IdentifiedVec -where - I: Eq + Hash + Clone + Debug, -{ - //////////////////// - // Constructors // - //////////////////// - - type ID = I; - type Element = E; - - /// Constructs a new, empty `IdentifiedVec` with the specified - /// `id_of_element` closure - #[inline] - fn new_identifying_element(id_of_element: fn(&E) -> I) -> Self { - Self { - order: Vec::new(), - elements: HashMap::new(), - _id_of_element: id_of_element, - } - } - - /// 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. - /// - /// You use this initializer to create an `identified_vec` when you have an arbitrary sequence of elements - /// that may not have unique ids. This initializer calls the `combine` closure with the current - /// and new elements for any duplicate ids. Pass a closure as `combine` that returns the element - /// to use in the resulting `identified_vec`: The closure can choose between the two elements, combine them - /// to produce a new element, or even throw an error. - /// - /// - Parameters: - /// - elements: A sequence of elements to use for the new `identified_vec`. - /// - 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` - /// 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, - ) -> Result - where - It: IntoIterator, - { - let mut _order = Vec::::new(); - let mut _elements = HashMap::::new(); - - for element in elements.into_iter() { - let id = id_of_element(&element); - match _elements.remove(&id) { - Some(existing) => match combine((_order.len(), &existing, &element)) { - Err(e) => return Err(e), - Ok(choice) => match choice { - ConflictResolutionChoice::ChooseFirst => { - _elements.insert(id.clone(), existing) - } - ConflictResolutionChoice::ChooseLast => { - _elements.insert(id.clone(), element) - } - }, - }, - None => { - _elements.insert(id.clone(), element); - _order.push(id); - None - } - }; - } - - Ok(Self { - order: _order, - _id_of_element: id_of_element, - elements: _elements, - }) - } - - /// 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. - /// - /// You use this initializer to create an `identified_vec` when you have an arbitrary sequence of elements - /// that may not have unique ids. This initializer calls the `combine` closure with the current - /// and new elements for any duplicate ids. Pass a closure as `combine` that returns the element - /// to use in the resulting `identified_vec`: The closure can choose between the two elements, combine them - /// to produce a new element, or even throw an error. - /// - /// - Parameters: - /// - elements: A sequence of elements to use for the new `identified_vec`. - /// - 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` - /// 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, - ) -> Self - where - It: IntoIterator, - { - let mut _order = Vec::::new(); - let mut _elements = HashMap::::new(); - - for element in elements.into_iter() { - let id = id_of_element(&element); - match _elements.remove(&id) { - Some(existing) => match combine((_order.len(), &existing, &element)) { - ConflictResolutionChoice::ChooseFirst => _elements.insert(id.clone(), existing), - ConflictResolutionChoice::ChooseLast => _elements.insert(id.clone(), element), - }, - None => { - _elements.insert(id.clone(), element); - _order.push(id); - None - } - }; - } - - Self { - order: _order, - _id_of_element: id_of_element, - elements: _elements, - } - } - - //////////////////// - // Public Get // - //////////////////// - - /// 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 - } - - /// Returns the number of elements in the `identified_vec`, also referred to as its 'length'. - #[inline] - fn len(&self) -> usize { - if cfg!(debug_assertions) { - assert_eq!(self.order.len(), self.elements.len()); - } - self.order.len() - } - - /// Returns the index for the given id. - /// - /// If an element identified by the given id is found in the `identified_vec`, this method returns an index - /// into the array that corresponds to the element. - /// - /// ``` - /// extern crate identified_vec; - /// use identified_vec::{IsIdentifiableVec, IdentifiedVec, Identifiable, IdentifiedVecOf}; - /// - /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] - /// struct User { - /// id: &'static str, - /// } - /// - /// impl User { - /// fn new(id: &'static str) -> Self { - /// Self { id } - /// } - /// } - /// - /// impl Identifiable for User { - /// type ID = &'static str; - /// fn id(&self) -> Self::ID { - /// self.id - /// } - /// } - /// - /// let mut users = - /// IdentifiedVecOf::::from_iter([User::new("u_42"), User::new("u_1729")]); - /// - /// assert_eq!(users.index_of_id(&"u_1729"), Some(1)); - /// assert_eq!(users.index_of_id(&"u_1337"), None); - /// ``` - /// - /// - 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. - #[inline] - fn index_of_id(&self, id: &Self::ID) -> Option { - self.order.iter().position(|i| i == id) - } - - /// 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. - #[inline] - fn get_mut(&mut self, id: &Self::ID) -> Option<&mut Self::Element> { - self.elements.get_mut(id) - } - - //////////////////// - // Public Get // - //////////////////// - - /// A read-only collection of references to the elements contained in this array, as a `Vec<&Elements>`. - /// - /// 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. - /// - /// - Complexity: O(n) - #[inline] - fn elements(&self) -> Vec<&Self::Element> { - self.iter().collect() - } - - /// Returns `true` if the `identified_vec` contains the `element.` - #[inline] - fn contains(&self, element: &Self::Element) -> 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 { - 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> { - 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> { - self.order.get(index).and_then(|id| self.get(id)) - } - - /// Append a new member to the end of the `identified_vec`, if the `identified_vec` doesn't already contain it. - /// - /// - Parameter item: The element to add to the `identified_vec`. - /// - Returns: 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`. - /// - 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. - #[inline] - fn append(&mut self, element: E) -> (bool, usize) { - self.insert(element, self.end_index()) - } - - /// 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. - #[inline] - fn append_other(&mut self, other: It) - where - It: IntoIterator, - { - other.into_iter().for_each(|i| _ = self.append(i)) - } - - /// 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. - /// - /// - Parameter item: The value to append or replace. - /// - 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. - #[inline] - fn update_or_append(&mut self, element: E) -> Option { - let id = self.id(&element); - self._update_value(element, id) - } - - /// Replace the member at the given index with a new value of the same identity. - /// - /// - Parameter item: The new value that should replace the original element. `item` must match - /// the identity of the original value. - /// - Parameter index: The index of the element to be replaced. - /// - Returns: The original element that was replaced. - /// - Complexity: Amortized O(1). - #[inline] - fn update_at(&mut self, element: E, index: usize) -> E { - let old_id = self - .order - .get(index) - .expect("Expected element at index {index}"); - let id = self.id(&element); - assert_eq!( - &id, old_id, - "The replacement item must match the identity of the original" - ); - return self - ._update_value_inserting_at(element, id, index) - .0 - .expect("Replaced old value"); - } - - /// Insert a new member to this identified_vec at the specified index, if the identified_vec doesn't already contain - /// it. - /// - /// - Parameter element: The element to insert. - /// - Returns: A pair `(inserted, index)`, where `inserted` is a Boolean value indicating whether - /// the operation added a new element, and `index` is the index of `element` in the resulting - /// identified_vec. If `inserted` is true, then the returned `index` may be different from the index - /// 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 - /// to make room in the storage identified_vec to add the inserted element.) - #[cfg(not(tarpaulin_include))] // false negative - #[inline] - fn insert(&mut self, element: E, at: usize) -> (bool, usize) { - let id = self.id(&element); - if let Some(existing) = self.index_of_id(&id) { - return (false, existing.clone()); - } - self._update_value_inserting_at(element, id, at); - (true, at) - } - - /// 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. - /// - /// - Parameter item: The value to append or replace. - /// - Parameter index: The index at which to insert the new member if `item` isn't already in the - /// set. - /// - 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. - #[inline] - fn update_or_insert(&mut self, element: E, index: usize) -> (Option, usize) { - let id = self.id(&element); - self._update_value_inserting_at(element, id, index) - } - - //////////////////// - // Public Remove // - //////////////////// - /// Removes the element identified by the given id from the `identified_vec`. - /// - /// ``` - /// extern crate identified_vec; - /// use identified_vec::{IsIdentifiableVec, IdentifiedVec, Identifiable, IdentifiedVecOf}; - /// - /// #[derive(Eq, PartialEq, Clone, Debug, Hash)] - /// struct User { - /// id: &'static str, - /// } - /// - /// impl User { - /// fn new(id: &'static str) -> Self { - /// Self { id } - /// } - /// } - /// - /// impl Identifiable for User { - /// type ID = &'static str; - /// fn id(&self) -> Self::ID { - /// self.id - /// } - /// } - /// - /// let mut users = - /// IdentifiedVecOf::::from_iter([User::new("u_42"), User::new("u_1729")]); - /// - /// assert_eq!(users.remove_by_id(&"u_1729"), Some(User::new("u_1729"))); - /// assert_eq!(users.elements(), [&User::new("u_42")]); - /// assert_eq!(users.remove_by_id(&"u_1337"), None); - /// assert_eq!(users.len(), 1); - /// ``` - /// - /// - 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`) - #[cfg(not(tarpaulin_include))] // false negative - #[inline] - fn remove_by_id(&mut self, id: &I) -> Option { - match self.index_of_id(id) { - Some(index) => { - self.order.remove(index); - return self.elements.remove(id); - } - None => { - assert!(!self.elements.contains_key(id)); - return None; - } - } - } - - /// Removes the given element from the `identified_vec`. - /// - /// If the element is found in the `identified_vec`, this method returns the element. - /// - /// If the element isn't found in the `identified_vec`, `remove` returns `None`. - /// - /// - 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`) - #[inline] - fn remove(&mut self, element: &E) -> Option { - self.remove_by_id(&self.id(element)) - } - - /// Removes and returns the element at the specified position. - /// - /// All the elements following the specified position are moved to close the resulting gap. - /// - /// - Parameter index: The position of the element to remove. - /// - Returns: The removed element. - /// - Precondition: `index` must be a valid index of the collection that is not equal to the - /// collection's end index. - /// - Complexity: O(`count`) - #[inline] - fn remove_at(&mut self, index: usize) -> E { - let id = self - .order - .get(index) - .expect("Precondition failure, index out of bounds"); - let removed = self - .elements - .remove(id) - .expect("Self::Element of existing id"); - self.order.remove(index); - return removed; - } - - /// Removes all the elements at the specified `offsets` from the `identified_vec`. - /// - /// - Parameter offsets: The offsets of all elements to be removed. - /// - Complexity: O(*n*) where *n* is the length of the `identified_vec`. - #[inline] - fn remove_at_offsets(&mut self, offsets: It) - where - It: IntoIterator, - { - let mut internal_offset = 0; - offsets.into_iter().for_each(|i| { - _ = self.remove_at(i - internal_offset); - internal_offset += 1; - }) - } -} - -impl IdentifiedVec -where - E: Clone, - I: Eq + Hash + Clone + Debug, -{ - /// A read-only collection of clones of the elements contained in this array, as a `Vec`. - /// - /// N.B. that this method is not constant time. - /// - /// Use `self.elements()` if you are looking for a collection of references. - /// - /// - Complexity: O(n) - #[inline] - pub fn items(&self) -> Vec { - self.iter().map(|e| e.clone()).collect() - } -} - -/// An iterator over the items of an `IdentifiedVec`. -pub struct IdentifiedVecIterator<'a, I, E> -where - I: Eq + Hash + Clone + Debug, -{ - identified_vec: &'a IdentifiedVec, - index: usize, -} - -impl<'a, I, E> Iterator for IdentifiedVecIterator<'a, I, E> -where - I: Eq + Hash + Clone + Debug, -{ - type Item = &'a E; - - fn next(&mut self) -> Option { - if self.index < self.identified_vec.len() { - let id = Some(&self.identified_vec.order[self.index]).unwrap(); - self.index += 1; - return self.identified_vec.get(id); - } else { - None - } - } -} - -impl IdentifiedVec -where - I: Eq + Hash + Clone + Debug, -{ - pub fn iter(&self) -> IdentifiedVecIterator { - IdentifiedVecIterator { - identified_vec: self, - index: 0, - } - } -} - -/// An owning iterator over the items of an `IdentifiedVec`. -pub struct IdentifiedVecIntoIterator -where - I: Eq + Hash + Clone + Debug, -{ - identified_vec: IdentifiedVec, -} - -impl Iterator for IdentifiedVecIntoIterator -where - I: Eq + Hash + Clone + Debug, -{ - type Item = E; - - fn next(&mut self) -> Option { - if self.identified_vec.len() == 0 { - return None; - } - let result = self.identified_vec.remove_at(0); - Some(result) - } -} - -impl IntoIterator for IdentifiedVec -where - I: Eq + Hash + Clone + Debug, -{ - type Item = E; - type IntoIter = IdentifiedVecIntoIterator; - - fn into_iter(self) -> Self::IntoIter { - Self::IntoIter { - identified_vec: self, - } - } -} - -impl IdentifiedVec where I: Eq + Hash + Clone + Debug {} - -/////////////////////// -//// Eq /// -/////////////////////// -impl PartialEq for IdentifiedVec -where - E: PartialEq, - I: Eq + Hash + Clone + Debug, -{ - fn eq(&self, other: &Self) -> bool { - self.elements() == other.elements() - } -} - -impl Eq for IdentifiedVec -where - E: Eq, - I: Eq + Hash + Clone + Debug, -{ -} - -/////////////////////// -//// Hash /// -/////////////////////// -impl Hash for IdentifiedVec -where - E: Hash, - I: Eq + Hash + Clone + Debug, -{ - fn hash(&self, state: &mut H) { - self.elements().hash(state); - } -} - -/////////////////////// -//// Display /// -/////////////////////// -impl Display for IdentifiedVec -where - E: Debug, - I: Eq + Hash + Clone + Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.elements().fmt(f) - } -} - -/////////////////////// -//// PRIVATE /// -/////////////////////// -impl IdentifiedVec -where - I: Eq + Hash + Clone + Debug, -{ - /// Next index for element appended - #[inline] - fn end_index(&self) -> usize { - self.len() - } - - /// Returns the Self::ID of an Self::Element - #[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. - #[cfg(not(tarpaulin_include))] // false negative - #[inline] - fn _insert_id_at(&mut self, id: I, index: usize) -> (bool, usize) { - match self.index_of_id(&id) { - Some(existing) => (false, existing), - None => { - self.order.insert(index, id); - (true, index) - } - } - } - - #[inline] - fn _update_value(&mut self, element: E, for_key: I) -> Option { - let value = element; - let key = for_key; - - let maybe_old = self.elements.remove(&key); - self.elements.insert(key.clone(), value); - - if maybe_old.is_some() { - return maybe_old; - } else { - self.order.push(key); - None - } - } - - #[inline] - fn _update_value_inserting_at( - &mut self, - element: E, - for_key: I, - index: usize, - ) -> (Option, usize) { - let id = for_key; - let value = element; - - let (inserted, offset) = self._insert_id_at(id.clone(), index); - if inserted { - assert_eq!(offset, index); - self.elements.insert(id.clone(), value); - return (None, offset); - } - let old = self.elements.remove(&id).expect("existing element"); - self.elements.insert(id, value); - return (Some(old), offset); - } -} - -/////////////////////// -//// DEBUG /// -/////////////////////// -impl IdentifiedVec -where - E: Debug, - I: Eq + Hash + Clone + Debug, -{ - #[cfg(not(tarpaulin_include))] - #[cfg(debug_assertions)] - pub fn debug(&self) { - println!("{}", self.debug_str()); - } - - #[cfg(debug_assertions)] - pub fn debug_str(&self) -> String { - format!("order: {:?}\nelements: {:?}", self.order, self.elements) - } -} diff --git a/src/vec_of.rs b/src/vec_of.rs deleted file mode 100644 index f915195..0000000 --- a/src/vec_of.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::collections::HashMap; - -#[cfg(feature = "serde")] -use std::fmt::Debug; - -#[cfg(feature = "serde")] -use crate::serde_error::IdentifiedVecOfSerdeFailure; -use crate::{ - identified_vec_of::Identifiable, - vec::{ConflictResolutionChoice, IdentifiedVec, IsIdentifiableVec}, -}; - -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; - -/////////////////////// -/// IdentifiedVecOf /// -/////////////////////// - -/// A type alias for `IdentifiedVec`, this is the -/// preferred and most powerful collection type of this crate, requires -/// that your `Element`s impl the `Identifiable` trait. Using this collection -/// allows you to skip passing the `id_of_element: fn(&Element) -> ID` closure -/// which you otherwise need to pass when initializing an `IdentifiedVec`. Using -/// `IdentifiedVecOf` together with feature "serde" also gives serde -/// serialization/deserialization as if it were a `Vec`, given that -/// `Element` implements serde serialization/deserialization of course. -pub type IdentifiedVecOf = IdentifiedVec<::ID, Element>; - -////////////////////////////////////////////// -/// Identifiable Element Constructors /// -////////////////////////////////////////////// -impl IdentifiedVec -where - Element: Identifiable, -{ - /// Constructs a new, empty `IdentifiedVec`, using `id()` on `Element` - /// as id function. - pub fn new() -> Self { - Self { - order: Vec::new(), - elements: HashMap::new(), - _id_of_element: |i| i.id(), - } - } - - /// Creates a new `IdentifiedVec` from the elements in the given sequence. - /// - /// You use this initializer to create an `IdentifiedVec` when you have a sequence of elements with unique - /// ids. Passing a sequence with duplicate ids to this initializer results in a runtime error. - /// - /// - Parameter elements: A sequence of elements to use for the new `IdentifiedVec`. Every element in - /// `elements` must have a unique id. - /// - Returns: A new `IdentifiedVec` initialized with the elements of `elements`. - /// - Precondition: The sequence must not have duplicate ids. - /// - Complexity: Expected O(*n*) on average, where *n* is the count of elements, if `ID` - /// implements high-quality hashing. - #[inline] - pub fn from_iter(unique_elements: I) -> Self - where - I: IntoIterator, - { - let mut _self = Self::new(); - unique_elements - .into_iter() - .for_each(|e| _ = _self.append(e)); - return _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 ids. - /// - /// You use this initializer to create an `identified_vec` when you have an arbitrary sequence of elements - /// that may not have unique ids. This initializer calls the `combine` closure with the current - /// and new elements for any duplicate ids. Pass a closure as `combine` that returns the element - /// to use in the resulting `identified_vec`: The closure can choose between the two elements, combine them - /// to produce a new element, or even throw an error. - /// - /// - Parameters: - /// - elements: A sequence of elements to use for the new `identified_vec`. - /// - 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 `ID` - /// implements high-quality hashing. - #[inline] - pub fn try_from_iter_select_unique_with( - elements: I, - combine: fn((usize, &Element, &Element)) -> Result, - ) -> Result - where - I: IntoIterator, - { - Self::try_from_iter_select_unique_ids_with(elements, |e| e.id(), combine) - } - - /// 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 ids. - /// - /// You use this initializer to create an `identified_vec` when you have an arbitrary sequence of elements - /// that may not have unique ids. This initializer calls the `combine` closure with the current - /// and new elements for any duplicate ids. Pass a closure as `combine` that returns the element - /// to use in the resulting `identified_vec`: The closure can choose between the two elements, combine them - /// to produce a new element, or even throw an error. - /// - /// - Parameters: - /// - elements: A sequence of elements to use for the new `identified_vec`. - /// - 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 `ID` - /// implements high-quality hashing. - #[inline] - pub fn from_iter_select_unique_with( - elements: I, - combine: fn((usize, &Element, &Element)) -> ConflictResolutionChoice, - ) -> Self - where - I: IntoIterator, - { - Self::from_iter_select_unique_ids_with(elements, |e| e.id(), combine) - } -} - -/////////////////////// -//// SERDE /// -/////////////////////// -#[cfg(feature = "serde")] -impl Serialize for IdentifiedVecOf -where - Element: Serialize + Identifiable + Debug + Clone, -{ - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer, - { - Vec::serialize(&self.elements(), serializer) - } -} - -#[cfg(feature = "serde")] -impl<'de, Element> Deserialize<'de> for IdentifiedVecOf -where - Element: Deserialize<'de> + Identifiable + Debug + Clone, -{ - #[cfg(not(tarpaulin_include))] // false negative - fn deserialize>( - deserializer: D, - ) -> Result, D::Error> { - let elements = Vec::::deserialize(deserializer)?; - IdentifiedVecOf::::try_from_iter_select_unique_with(elements, |(idx, _, _)| { - Err(IdentifiedVecOfSerdeFailure::DuplicateElementsAtIndex(idx)) - }) - .map_err(de::Error::custom) - } -}