Skip to content

Commit

Permalink
feat(macros): introduce register_blazemap_id_wrapper and `register_…
Browse files Browse the repository at this point in the history
…blazemap_id`
  • Loading branch information
andrewsonin committed Dec 15, 2023
1 parent 7cbb729 commit 5d91d0b
Show file tree
Hide file tree
Showing 11 changed files with 457 additions and 131 deletions.
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ slab-like map with an interface similar to that of `HashMap`._
Let's imagine that at runtime you create a small number of clumsy objects that are used as keys in hashmaps.

This crate allows you to seamlessly replace them with lightweight identifiers in a slab-like manner
using the `register_blazemap_id` macro as well as using them as keys in the `BlazeMap`
using the `register_blazemap_id` and `register_blazemap_id_wrapper` macros as well as using them as keys in
the `BlazeMap`
— a vector-based slab-like map with an interface similar to that of `HashMap`.

## Graphical representation of the old approach
Expand All @@ -17,7 +18,9 @@ using the `register_blazemap_id` macro as well as using them as keys in the `Bla

![NewApproach.svg](./docs/drawio/README_-_NewApproach.svg)

## `register_blazemap_id` macro
## `register_blazemap_id_wrapper` macro

Creates a new type that is compatible as a key-wrapper for `blazemap` collections.

This macro supports optional inference of standard traits using the following syntax:

Expand All @@ -44,12 +47,30 @@ This macro supports optional inference of standard traits using the following sy
* `PartialOrd` (mutually exclusive with `Ord`)
* `Ord` (also derives `PartialOrd`, so mutually exclusive with `PartialOrd`)

## `register_blazemap_id` macro

Creates a new type based on `usize` that is compatible as a key-wrapper for `blazemap` collections.

This macro supports optional inference of standard traits using the following syntax:

* `Derive` — derives traits in the same way as for
the serial number assigned when creating a new instance of the type.
Because methods inferred by this option do not require additional
locking on synchronization primitives,
they do not incur any additional overhead compared to methods inferred for plain `usize`.
This method supports inference of the following traits:
* `PartialOrd` (mutually exclusive with `Ord`)
* `Ord` (also derives `PartialOrd`, so mutually exclusive with `PartialOrd`)
* `Serialize` (with `serde` feature only)

### Example

## `register_blazemap_id_wrapper` macro

```rust
use blazemap::prelude::{BlazeMap, register_blazemap_id};
use blazemap::prelude::{BlazeMap, register_blazemap_id_wrapper};

register_blazemap_id! {
register_blazemap_id_wrapper! {
pub struct BlazeMapId(String);
Derive(as for Original Type): { // Optional section
Debug,
Expand All @@ -70,4 +91,28 @@ map.insert(key_1, "1");
map.insert(key_3, "3");

assert_eq!(format!("{map:?}"), r#"{"first": "1", "second": "2", "third": "3"}"#)
```

## `register_blazemap_id` macro

```rust
use blazemap::prelude::{BlazeMap, register_blazemap_id};

register_blazemap_id! {
pub struct BlazeMapIdExample(start from: 1); // "(start from: number)" is optional
Derive: { // Derive section is also optional
Ord
};
}

let key_1 = BlazeMapIdExample::new();
let key_2 = BlazeMapIdExample::new();
let key_3 = BlazeMapIdExample::new();

let mut map = BlazeMap::new();
map.insert(key_2, "2");
map.insert(key_1, "1");
map.insert(key_3, "3");

assert_eq!(format!("{map:?}"), r#"{1: "1", 2: "2", 3: "3"}"#)
```
50 changes: 31 additions & 19 deletions src/collections/blazemap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::borrow::Borrow;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;

use read_write_api::ReadApi;
use read_write_api::{ReadApi, UpgradableReadApi};
#[cfg(feature = "serde")]
use serde::{
de::{MapAccess, Visitor},
Expand All @@ -17,8 +18,9 @@ pub use crate::collections::blazemap::{
iter::{Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut},
};
use crate::collections::blazemap::entry::VacantEntryInner;
use crate::id_wrapper::IdWrapper;
use crate::orig_type_id_map::OrigTypeIdMap;
use crate::id_wrapper::BlazeMapId;
use crate::orig_type_id_map::{InsertableStaticInfoApi, StaticInfoApi};
use crate::prelude::BlazeMapIdWrapper;

mod entry;
mod iter;
Expand Down Expand Up @@ -139,7 +141,7 @@ impl<K, V> BlazeMap<K, V>

impl<K, V> BlazeMap<K, V>
where
K: IdWrapper
K: BlazeMapId
{
/// Creates a new instance of the [`BlazeMap`]
/// with capacity equal to the current total number of unique `K` instances.
Expand Down Expand Up @@ -262,7 +264,7 @@ impl<K, V> BlazeMap<K, V>

impl<K, V> IntoIterator for BlazeMap<K, V>
where
K: IdWrapper
K: BlazeMapId
{
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
Expand All @@ -277,7 +279,7 @@ impl<K, V> IntoIterator for BlazeMap<K, V>

impl<'a, K, V> IntoIterator for &'a BlazeMap<K, V>
where
K: IdWrapper
K: BlazeMapId
{
type Item = (K, &'a V);
type IntoIter = Iter<'a, K, V>;
Expand All @@ -290,7 +292,7 @@ impl<'a, K, V> IntoIterator for &'a BlazeMap<K, V>

impl<'a, K, V> IntoIterator for &'a mut BlazeMap<K, V>
where
K: IdWrapper
K: BlazeMapId
{
type Item = (K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
Expand All @@ -303,7 +305,7 @@ impl<'a, K, V> IntoIterator for &'a mut BlazeMap<K, V>

impl<K, V> FromIterator<(K, V)> for BlazeMap<K, V>
where
K: IdWrapper
K: BlazeMapId
{
#[inline]
fn from_iter<T: IntoIterator<Item=(K, V)>>(iter: T) -> Self {
Expand Down Expand Up @@ -340,22 +342,26 @@ macro_rules! blaze_map_orig_key_blocking_iter {

impl<K, V> Debug for BlazeMap<K, V>
where
K: IdWrapper,
<K as IdWrapper>::OrigType: Debug,
K: BlazeMapId,
<K as BlazeMapId>::OrigType: Debug,
V: Debug
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
blaze_map_orig_key_blocking_iter!(self, iter, guard);
f.debug_map().entries(iter).finish()
let mut debug_map = f.debug_map();
for (key, value) in iter {
debug_map.entry(key.borrow(), value);
}
debug_map.finish()
}
}

#[cfg(feature = "serde")]
impl<K, V> Serialize for BlazeMap<K, V>
where
K: IdWrapper,
<K as IdWrapper>::OrigType: Serialize,
K: BlazeMapId,
<K as BlazeMapId>::OrigType: Serialize,
V: Serialize
{
#[inline]
Expand All @@ -366,7 +372,7 @@ impl<K, V> Serialize for BlazeMap<K, V>
blaze_map_orig_key_blocking_iter!(self, iter, guard);
let mut serializer = serializer.serialize_map(Some(self.len))?;
for (key, value) in iter {
serializer.serialize_entry(key, value)?;
serializer.serialize_entry(key.borrow(), value)?;
}
serializer.end()
}
Expand All @@ -375,8 +381,10 @@ impl<K, V> Serialize for BlazeMap<K, V>
#[cfg(feature = "serde")]
impl<'de, K, V> Deserialize<'de> for BlazeMap<K, V>
where
K: IdWrapper,
<K as IdWrapper>::OrigType: Deserialize<'de>,
K: BlazeMapIdWrapper,
<K as BlazeMapId>::OrigType: Deserialize<'de>,
<K as BlazeMapId>::StaticInfoApi: InsertableStaticInfoApi<<K as BlazeMapId>::OrigType>,
<K as BlazeMapId>::StaticInfoApiLock: UpgradableReadApi,
V: Deserialize<'de>
{
#[inline]
Expand All @@ -391,13 +399,17 @@ impl<'de, K, V> Deserialize<'de> for BlazeMap<K, V>
#[cfg(feature = "serde")]
struct BlazeMapDeserializer<K, V>(PhantomData<(K, V)>)
where
K: IdWrapper;
K: BlazeMapIdWrapper,
<K as BlazeMapId>::StaticInfoApi: InsertableStaticInfoApi<<K as BlazeMapId>::OrigType>,
<K as BlazeMapId>::StaticInfoApiLock: UpgradableReadApi;

#[cfg(feature = "serde")]
impl<'de, K, V> Visitor<'de> for BlazeMapDeserializer<K, V>
where
K: IdWrapper,
<K as IdWrapper>::OrigType: Deserialize<'de>,
K: BlazeMapIdWrapper,
<K as BlazeMapId>::OrigType: Deserialize<'de>,
<K as BlazeMapId>::StaticInfoApi: InsertableStaticInfoApi<<K as BlazeMapId>::OrigType>,
<K as BlazeMapId>::StaticInfoApiLock: UpgradableReadApi,
V: Deserialize<'de>
{
type Value = BlazeMap<K, V>;
Expand Down
16 changes: 8 additions & 8 deletions src/collections/blazemap/entry.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::prelude::IdWrapper;
use crate::prelude::BlazeMapId;

#[derive(Debug)]
/// A view into a single entry in a map, which may either be vacant or occupied.
Expand All @@ -9,7 +9,7 @@ use crate::prelude::IdWrapper;
/// [`entry`]: crate::collections::blazemap::BlazeMap::entry
pub enum Entry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
/// An occupied entry.
Occupied(OccupiedEntry<'a, K, V>),
Expand All @@ -22,7 +22,7 @@ pub enum Entry<'a, K, V>
/// It is part of the [`Entry`] enum.
pub struct OccupiedEntry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
pub(in crate::collections::blazemap)
key: K,
Expand All @@ -39,7 +39,7 @@ pub struct OccupiedEntry<'a, K, V>
/// It is part of the [`Entry`] enum.
pub struct VacantEntry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
pub(in crate::collections::blazemap)
key: K,
Expand All @@ -60,7 +60,7 @@ enum VacantEntryInner<'a, V> {

impl<'a, K, V> Entry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
/// Ensures a value is in the entry by inserting the default if empty,
/// and returns a mutable reference to the value in the entry.
Expand Down Expand Up @@ -107,7 +107,7 @@ impl<'a, K, V> Entry<'a, K, V>

impl<'a, K, V> Entry<'a, K, V>
where
K: IdWrapper,
K: BlazeMapId,
V: Default
{
/// Ensures a value is in the entry by inserting the default value if empty,
Expand All @@ -123,7 +123,7 @@ impl<'a, K, V> Entry<'a, K, V>

impl<'a, K, V> OccupiedEntry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
/// Gets the key in the entry.
#[inline]
Expand Down Expand Up @@ -193,7 +193,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V>

impl<'a, K, V> VacantEntry<'a, K, V>
where
K: IdWrapper
K: BlazeMapId
{
/// Gets the key that would be used when inserting a value through the [`VacantEntry`].
#[inline]
Expand Down
Loading

0 comments on commit 5d91d0b

Please sign in to comment.