Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infra #6

Merged
merged 3 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "identified_vec"
version = "0.1.2"
version = "0.1.3"
edition = "2021"
authors = ["Alexander Cyon <[email protected]>"]
description = "Like HashSet but retaining INSERTION order and without `Hash` requirement on the Element type."
Expand All @@ -10,16 +10,17 @@ repository = "https://github.com/Sajjon/identified_vec"
keywords = ["identifiable", "vec", "orderset", "set", "hashset"]
categories = ["data-structures"]

[features]
serde = ["dep:serde"]
id_prim = []

[dependencies]
anyerror = "0.1.12"
serde = { version = "1.0.193", optional = true }
thiserror = "1.0.50"

[features]
default = ["serde"]
serde = ["dep:serde"]

[dev-dependencies]
identified_vec = { path = ".", features = ["id_prim", "serde"] }
serde = "1.0.193"
serde_json = "1.0.108"
rand = "0.8.5"
Expand Down
56 changes: 40 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# `identified_vec`

[![codecov](https://codecov.io/github/Sajjon/identified_vec/graph/badge.svg?token=Em6TayrP8j)](https://codecov.io/github/Sajjon/identified_vec)
[![Code Coverage](https://codecov.io/github/Sajjon/identified_vec/graph/badge.svg?token=Em6TayrP8j)](https://codecov.io/github/Sajjon/identified_vec)
[![Crates.io](https://img.shields.io/crates/v/identified_vec.svg)](https://crates.io/crates/identified_vec)
[![Documentation](https://docs.rs/identified_vec/badge.svg)](https://docs.rs/identified_vec)
[![Rust](https://img.shields.io/badge/rust-1.73.0%2B-blue.svg?maxAge=3600)](https://github.com/Sajjon/identified_vec)

A collection of unique identifiable elements which retains **insertion** order, inspired by [Pointfree's Swift Identified Collections](https://github.com/pointfreeco/swift-identified-collections).

Expand All @@ -10,11 +13,11 @@ Similar to the standard `Vec`, the `IdentifiedVec` maintain their elements in a

You can create an identified vec with any element type that implements the `Identifiable` trait.

# Example

```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 All @@ -34,14 +37,22 @@ impl User {
*self.name.borrow()
}
}
```

## Identifiable

```rust
impl Identifiable for User {
type ID = &'static str;
fn id(&self) -> Self::ID {
self.id
}
}
```

## `from_iter`

```rust
let mut users = IdentifiedVecOf::<User>::from_iter([
User::new("u_42", "Satoshi Nakamoto"),
User::new("u_1337", "Leia Skywalker"),
Expand All @@ -56,7 +67,11 @@ assert_eq!(
users.get_at_index(1).map(|u| u.name()),
Some("Leia Skywalker")
);
```

## `append` & `elements()`

```rust
users.append(User::new("u_237", "Alan Turing"));
assert_eq!(
users.elements(),
Expand All @@ -81,7 +96,11 @@ assert_eq!(
.iter()
.collect::<Vec<&User>>()
);
```

## `update_or_insert`

```rust
// 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);
Expand All @@ -95,7 +114,11 @@ assert_eq!(
.iter()
.collect::<Vec<&User>>()
);
```

## `update_or_append`

```rust
// or `update_or_append`
users.update_or_append(User::new("u_237", "Marie Curie"));
assert_eq!(
Expand All @@ -108,7 +131,11 @@ assert_eq!(
.iter()
.collect::<Vec<&User>>()
);
```

## `get_mut`

```rust
// or mutate with `get_mut(id)`
*users.get_mut(&"u_1337").unwrap().name.get_mut() = "Yoda";
assert_eq!(
Expand All @@ -126,27 +153,24 @@ assert_eq!(
Or you can provide a closure that describes an element's identity:

```rust
use identified_vec::identified_vec::IdentifiedVec;
use identified_vec::identifiable::Identifiable;
use identified_vec::identified_vec_of::IdentifiedVecOf;

let numbers = IdentifiedVec::<u32, u32>::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`.

# Features

## Serde
## Flags

The `IdentifiedVecOf` type (which `Element` impl `Identifiable` trait) is `serde::Serializable` and `serde::Deserializable` as `Vec`.
This crate has the following Cargo features:

```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.
162 changes: 157 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +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);
//! ```

#[cfg(feature = "serde")]
pub mod serde_error;
mod identifiable_trait;
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<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 = "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::*;
26 changes: 26 additions & 0 deletions src/primitives_identifiable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![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);
Loading
Loading