Skip to content

Commit

Permalink
documentation efforts and proj restructure and id_prim feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajjon committed Dec 10, 2023
1 parent 1f84dc5 commit fd7bde5
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 62 deletions.
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ You can create an identified vec with any element type that implements the `Iden

```rust
extern crate identified_vec;
use identified_vec::identified_vec::IdentifiedVec;
use identified_vec::identifiable::Identifiable;
use identified_vec::identified_vec_of::IdentifiedVecOf;
use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf};
use std::cell::RefCell;

#[derive(Eq, PartialEq, Clone, Debug)]
Expand Down Expand Up @@ -162,16 +160,17 @@ let numbers = IdentifiedVec::<u32, u32>::new_identifying_element(|e| *e);

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`.

# Features
## Flags

## Serde
This crate has the following Cargo features:

The `IdentifiedVecOf` type (which `Element` impl `Identifiable` trait) is `serde::Serializable` and `serde::Deserializable` as `Vec`.

```toml
identified_vec = { version = "0.1.2", features = ["serde"] }
```
- `serde`: Enables serde serialization support on `IdentifiedVecOf` type (which `Element` impl `Identifiable` trait).
- `id_prim`: Get impl of trait `Identifiable` for primitives: `i8`,.., `i128`, `u8`, ..., `u128` and `bool` (not so useful, allows for only two elements in `IdentifiedVecOf`, but who am I to discriminate.)

## Implementation Details

An identified vec consists of a `Vec` of `ID`s keeping insertion order and a `HashMap` of id-element pairs, for contsant time lookip of element given an ID.
An identified vec consists of a `Vec` of `ID`s keeping insertion order and a `HashMap` of id-element pairs, for constant time lookup of element given an ID.

## License

Licensed under MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
File renamed without changes.
165 changes: 154 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,158 @@
pub mod identifiable;
pub mod identified_vec;
pub mod identified_vec_of;
//! 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::{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::<User>::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::<Vec<&User>>()
//! );
//!
//! // 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::<Vec<&User>>()
//! );
//!
//! // 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::<Vec<&User>>()
//! );
//!
//! // 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::<Vec<&User>>()
//! );
//!
//! // 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::<Vec<&User>>()
//! );
//! ```
//!
//! Or you can provide a closure that describes an element's identity:
//!
//! ```
//! extern crate identified_vec;
//! use identified_vec::{IdentifiedVec, IdentifiedVecOf, Identifiable};
//! let numbers = IdentifiedVec::<u32, u32>::new_identifying_element(|e| *e);
//! ```
pub mod primitives_identifiable;
mod identifiable_trait;
mod primitives_identifiable;
mod serde_error;
mod vec;
mod vec_of;

pub use identifiable::*;
pub use identified_vec::*;
pub use identified_vec_of::*;
pub mod identified_vec {
//! A collection of unique identifiable elements which retains **insertion** order.
pub use crate::vec::*;
}

#[cfg(feature = "serde")]
pub mod serde_error;
pub mod identified_vec_of {
//! The `Identifiable` trait allows you to use the
//! `IdentifiedVecOf<User> instead of the more verbose
//! `IdentifiedVec<SomeUserID, User>` 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 = "serde")]
pub use serde_error::*;
#[cfg(feature = "id_prim")]
pub use crate::primitives_identifiable::*;

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

pub use crate::identified_vec::*;
pub use crate::identified_vec_of::*;
39 changes: 22 additions & 17 deletions src/primitives_identifiable.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
#![cfg(feature = "id_prim")]

use crate::Identifiable;
use crate::identified_vec_of::Identifiable;

// macro_rules! impl_identifiable {
// ($primitive_type:ident) => {
// impl Identifiable for $primitive_type {
// type ID = $primitive_type;
// fn id(&self) -> Self::ID {
// return self.clone();
// }
// }
// };
// }

impl Identifiable for i32 {
type ID = i32;
fn id(&self) -> Self::ID {
*self
}
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);
16 changes: 4 additions & 12 deletions src/identified_vec.rs → src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ pub enum ConflictResolutionChoice {
///
/// ```
/// extern crate identified_vec;
/// use identified_vec::identified_vec::IdentifiedVec;
/// use identified_vec::identifiable::Identifiable;
/// use identified_vec::identified_vec_of::IdentifiedVecOf;
/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf};
/// use std::cell::RefCell;
///
/// #[derive(Eq, PartialEq, Clone, Debug)]
Expand Down Expand Up @@ -146,9 +144,7 @@ pub enum ConflictResolutionChoice {
///
/// ```
/// /// extern crate identified_vec;
/// use identified_vec::identified_vec::IdentifiedVec;
/// use identified_vec::identifiable::Identifiable;
/// use identified_vec::identified_vec_of::IdentifiedVecOf;
/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf};
///
/// let numbers = IdentifiedVec::<u32, u32>::new_identifying_element(|e| *e);
/// ```
Expand Down Expand Up @@ -363,9 +359,7 @@ where
///
/// ```
/// extern crate identified_vec;
/// use identified_vec::identified_vec::IdentifiedVec;
/// use identified_vec::identifiable::Identifiable;
/// use identified_vec::identified_vec_of::IdentifiedVecOf;
/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf};
///
/// #[derive(Eq, PartialEq, Clone, Debug, Hash)]
/// struct User {
Expand Down Expand Up @@ -647,9 +641,7 @@ where
///
/// ```
/// extern crate identified_vec;
/// use identified_vec::identified_vec::IdentifiedVec;
/// use identified_vec::identifiable::Identifiable;
/// use identified_vec::identified_vec_of::IdentifiedVecOf;
/// use identified_vec::{IdentifiedVec, Identifiable, IdentifiedVecOf};
///
/// #[derive(Eq, PartialEq, Clone, Debug, Hash)]
/// struct User {
Expand Down
9 changes: 4 additions & 5 deletions src/identified_vec_of.rs → src/vec_of.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use crate::{
identifiable::Identifiable,
identified_vec::{ConflictResolutionChoice, IdentifiedVec},
};

use anyerror::AnyError;
use std::collections::HashMap;
use std::fmt::Debug;

#[cfg(feature = "serde")]
use crate::serde_error::IdentifiedVecOfSerdeFailure;
use crate::{
identified_vec_of::Identifiable,
vec::{ConflictResolutionChoice, IdentifiedVec},
};

#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
Expand Down
15 changes: 9 additions & 6 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use identified_vec::{

#[derive(Eq, PartialEq, Clone)]
pub struct User {
pub id: i32,
pub id: u16,
pub name: RefCell<String>,
}

impl User {
fn new(id: i32, name: &str) -> Self {
fn new(id: u16, name: &str) -> Self {
if name.is_empty() {
panic!("name cannot be empty")
}
Expand All @@ -34,6 +35,7 @@ impl User {
User::new(3, "Blob, Sr.")
}
}

impl Debug for User {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("User")
Expand All @@ -42,14 +44,15 @@ impl Debug for User {
.finish()
}
}

impl Identifiable for User {
type ID = i32;
type ID = u16;
fn id(&self) -> Self::ID {
self.id
}
}

type SUT = IdentifiedVecOf<i32>;
type SUT = IdentifiedVecOf<u32>;
type Users = IdentifiedVecOf<User>;

#[test]
Expand Down Expand Up @@ -108,7 +111,7 @@ fn get() {
assert_eq!(identified_vec.get(&3), Some(&User::blob_sr()));

// 1
let mut id: &i32 = &1;
let mut id: &u16 = &1;
identified_vec
.get_mut(id)
.unwrap()
Expand Down Expand Up @@ -530,7 +533,7 @@ fn display() {
fn hash() {
let identified_vec = SUT::from_iter([1, 2, 3]);
assert_eq!(
HashSet::<IdentifiedVec<i32, i32>>::from_iter([identified_vec.clone()]),
HashSet::<IdentifiedVec<u32, u32>>::from_iter([identified_vec.clone()]),
HashSet::from_iter([identified_vec.clone(), identified_vec])
)
}

0 comments on commit fd7bde5

Please sign in to comment.