diff --git a/Cargo.toml b/Cargo.toml index 4c68151..3c85533 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blazemap" -version = "0.0.3" +version = "0.0.4" authors = ["Andrew Sonin "] categories = ["data-structures"] description = """ @@ -16,6 +16,7 @@ edition = "2021" [dependencies] once_cell = "1" parking_lot = "0.12" +read-write-api = "0.17" serde = { version = "1", optional = true, features = ["derive"] } [dev-dependencies] diff --git a/src/collections/blazemap.rs b/src/collections/blazemap.rs index 422cc59..320794c 100644 --- a/src/collections/blazemap.rs +++ b/src/collections/blazemap.rs @@ -1,6 +1,7 @@ use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; +use read_write_api::ReadApi; #[cfg(feature = "serde")] use serde::{ de::{MapAccess, Visitor}, @@ -17,6 +18,7 @@ pub use crate::collections::blazemap::{ }; use crate::collections::blazemap::entry::VacantEntryInner; use crate::id_wrapper::IdWrapper; +use crate::orig_type_id_map::OrigTypeIdMap; mod entry; mod iter; @@ -322,7 +324,8 @@ impl Default for BlazeMap macro_rules! blaze_map_orig_key_blocking_iter { ($self:ident, $iter:ident, $guard:ident) => { - let $guard = K::static_info().read(); + let $guard = K::static_info(); + let $guard = $guard.read(); let $iter = $self.inner.iter() .enumerate() .filter_map(|(idx, value)| Some((idx, value.as_ref()?))) diff --git a/src/collections/blazemap/iter.rs b/src/collections/blazemap/iter.rs index 44f29c4..99473cd 100644 --- a/src/collections/blazemap/iter.rs +++ b/src/collections/blazemap/iter.rs @@ -3,7 +3,10 @@ use std::marker::PhantomData; use std::mem::needs_drop; use std::panic::{RefUnwindSafe, UnwindSafe}; +use read_write_api::ReadApi; + use crate::collections::blazemap::BlazeMap; +use crate::orig_type_id_map::OrigTypeIdMap; use crate::prelude::IdWrapper; /// An iterator over the entries of a [`BlazeMap`]. @@ -550,7 +553,8 @@ impl<'a, K, V> Debug for Iter<'a, K, V> { #[inline] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - let static_info = K::static_info().read(); + let static_info = K::static_info(); + let static_info = static_info.read(); let iter = self.map( |(key, value)| { let key = unsafe { static_info.get_key_unchecked(key.get_index()) }; @@ -612,7 +616,8 @@ impl<'a, K, V> Debug for Keys<'a, K, V> { #[inline] fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - let static_info = K::static_info().read(); + let static_info = K::static_info(); + let static_info = static_info.read(); let iter = self.map( |key| unsafe { static_info.get_key_unchecked(key.get_index()) } ); diff --git a/src/id_wrapper.rs b/src/id_wrapper.rs index ad33efb..fb3c108 100644 --- a/src/id_wrapper.rs +++ b/src/id_wrapper.rs @@ -1,8 +1,8 @@ use std::hash::Hash; -use parking_lot::{RwLock, RwLockUpgradableReadGuard}; +use read_write_api::{RwApi, UpgradableReadApi, UpgradableReadGuard}; -use crate::utils::StaticInfo; +use crate::orig_type_id_map::OrigTypeIdMap; /// Provides interface for `blazemap` key-wrapper types /// defined by the [`register_blazemap_id`](crate::register_blazemap_id) macro. @@ -11,15 +11,22 @@ pub trait IdWrapper: Copy /// Original key type. type OrigType: 'static + Clone + Eq + Hash; + #[doc(hidden)] + type OrigTypeIdMap: 'static + OrigTypeIdMap; + + #[doc(hidden)] + type OrigTypeIdMapApi: RwApi; + /// Creates a new instance of [`Self`] based on the [`Self::OrigType`] instance. #[inline] fn new(key: Self::OrigType) -> Self { unsafe { - let guard = Self::static_info().upgradable_read(); + let mut static_info = Self::static_info(); + let guard = static_info.upgradable_read(); if let Some(index) = guard.get_index(&key) { Self::from_index_unchecked(index) } else { - let mut guard = RwLockUpgradableReadGuard::upgrade(guard); + let mut guard = guard.upgrade(); let index = guard.insert_new_key_unchecked(key); Self::from_index_unchecked(index) } @@ -33,5 +40,5 @@ pub trait IdWrapper: Copy unsafe fn from_index_unchecked(index: usize) -> Self; #[doc(hidden)] - fn static_info() -> &'static RwLock>; + fn static_info() -> Self::OrigTypeIdMapApi; } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fbb7b2e..91ebe41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,8 @@ pub mod utils; /// Collection types. pub mod collections; mod macros; +#[doc(hidden)] +mod orig_type_id_map; /// Crate prelude. pub mod prelude { diff --git a/src/macros.rs b/src/macros.rs index 084dd34..ab5f5e7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -112,6 +112,8 @@ macro_rules! blazemap_inner { impl $crate::prelude::IdWrapper for $new_type { type OrigType = $orig_type; + type OrigTypeIdMap = $crate::utils::StaticInfo<$orig_type>; + type OrigTypeIdMapApi = &'static $crate::external::parking_lot::RwLock<&'static mut $crate::utils::StaticInfo<$orig_type>>; #[inline] fn get_index(self) -> usize { @@ -125,13 +127,15 @@ macro_rules! blazemap_inner { } #[inline] - fn static_info() -> &'static $crate::external::parking_lot::RwLock<$crate::utils::StaticInfo<$orig_type>> + fn static_info() -> &'static $crate::external::parking_lot::RwLock<&'static mut $crate::utils::StaticInfo<$orig_type>> { use $crate::external::once_cell::sync::Lazy; use $crate::external::parking_lot::RwLock; use $crate::utils::StaticInfo; - static MAP: Lazy>> = Lazy::new( - || RwLock::new(StaticInfo::new()) + + static mut STATIC_INFO: StaticInfo<$orig_type> = StaticInfo::new(); + static MAP: Lazy>> = Lazy::new( + || RwLock::new(unsafe { &mut STATIC_INFO }) ); &MAP } @@ -155,7 +159,10 @@ macro_rules! blazemap_derive_key_inner { impl PartialOrd for $new_type { #[inline] - fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> { + fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> + { + use $crate::orig_type_id_map::OrigTypeIdMap; + let Self(lhs) = self; let Self(rhs) = other; let guard = ::static_info().read(); @@ -181,7 +188,10 @@ macro_rules! blazemap_derive_key_inner { impl Ord for $new_type { #[inline] - fn cmp(&self, other: &Self) -> ::std::cmp::Ordering { + fn cmp(&self, other: &Self) -> ::std::cmp::Ordering + { + use $crate::orig_type_id_map::OrigTypeIdMap; + let Self(lhs) = self; let Self(rhs) = other; let guard = ::static_info().read(); @@ -201,6 +211,8 @@ macro_rules! blazemap_derive_key_inner { #[inline] fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use $crate::orig_type_id_map::OrigTypeIdMap; + let Self(index) = self; let mut f = f.debug_struct(::std::stringify!($new_type)); let guard = ::static_info().read(); @@ -219,6 +231,8 @@ macro_rules! blazemap_derive_key_inner { #[inline] fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use $crate::orig_type_id_map::OrigTypeIdMap; + let Self(index) = self; let guard = ::static_info().read(); let original_key = unsafe { guard.get_key_unchecked(index.into_inner()) }; @@ -248,6 +262,8 @@ macro_rules! blazemap_derive_key_inner { where S: $crate::external::serde::Serializer { + use $crate::orig_type_id_map::OrigTypeIdMap; + let Self(index) = self; unsafe { ::static_info() diff --git a/src/orig_type_id_map.rs b/src/orig_type_id_map.rs new file mode 100644 index 0000000..7c16610 --- /dev/null +++ b/src/orig_type_id_map.rs @@ -0,0 +1,11 @@ +#[doc(hidden)] +pub trait OrigTypeIdMap +{ + fn num_elems(&self) -> usize; + + fn get_index(&self, key: &K) -> Option; + + unsafe fn get_key_unchecked(&self, index: usize) -> &K; + + unsafe fn insert_new_key_unchecked(&mut self, key: K) -> usize; +} \ No newline at end of file diff --git a/src/utils/static_info.rs b/src/utils/static_info.rs index a192924..252b7e0 100644 --- a/src/utils/static_info.rs +++ b/src/utils/static_info.rs @@ -3,6 +3,8 @@ use std::hash::Hash; use once_cell::sync::Lazy; +use crate::orig_type_id_map::OrigTypeIdMap; + /// Global, statically initialized structure that contains correspondence mapping /// between blazemap index wrappers and original keys. #[doc(hidden)] @@ -24,31 +26,27 @@ impl StaticInfo } } -impl StaticInfo +impl OrigTypeIdMap for StaticInfo where K: Clone + Eq + Hash { #[inline(always)] - pub(in crate) fn num_elems(&self) -> usize { self.index_to_orig.len() } #[inline] - pub(in crate) fn get_index(&self, key: &K) -> Option { self.orig_to_index.get(key).copied() } #[inline] - pub unsafe fn get_key_unchecked(&self, index: usize) -> &K { self.index_to_orig.get_unchecked(index) } #[inline] - pub(in crate) unsafe fn insert_new_key_unchecked(&mut self, key: K) -> usize {