Add initial map implementations
Signed-off-by: trivernis <trivernis@protonmail.com>main
commit
14e369449e
@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
.idea
|
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "trait-bound-typemap"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
description = "A crate to create typemaps with additional trait restrictions and implementations"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
multi-trait-object = "0.2.0"
|
@ -0,0 +1,33 @@
|
||||
# Trait bound Typemap
|
||||
|
||||
This crate offers typemaps that restrict a given type in their
|
||||
trait and therefore offer additional trait implementations such as `Clone`.
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use trait_bound_typemap::{CloneTypeMap, TypeMapTrait, TypeMapKey};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MyStruct {
|
||||
a: u8,
|
||||
b: String,
|
||||
}
|
||||
|
||||
pub struct MyStructKey;
|
||||
|
||||
impl TypeMapKey for MyStructKey {
|
||||
type Value = MyStruct;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut map = CloneTypeMap::new();
|
||||
let value = MyStruct {a: 5, b: String::from("Hello World")};
|
||||
map.insert::<MyStructKey>(value);
|
||||
assert!(map.contains_key::<MyStructKey>());
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
@ -0,0 +1,38 @@
|
||||
use multi_trait_object::MultitraitObject;
|
||||
use std::any::TypeId;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct TypeMapBase(pub(crate) HashMap<TypeId, MultitraitObject>);
|
||||
|
||||
impl TypeMapBase {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert<K: 'static>(&mut self, value: MultitraitObject) {
|
||||
self.0.insert(TypeId::of::<K>(), value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get<K: 'static>(&self) -> Option<&MultitraitObject> {
|
||||
self.0.get(&TypeId::of::<K>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mut<K: 'static>(&mut self) -> Option<&mut MultitraitObject> {
|
||||
self.0.get_mut(&TypeId::of::<K>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove<K: 'static>(&mut self) -> Option<MultitraitObject> {
|
||||
self.0.remove(&TypeId::of::<K>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains_key<K: 'static>(&self) -> bool {
|
||||
self.0.contains_key(&TypeId::of::<K>())
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#![doc=include_str!("../README.md")]
|
||||
|
||||
mod base;
|
||||
pub(crate) mod macros;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod trait_maps;
|
||||
mod typemap_trait;
|
||||
|
||||
pub use trait_maps::*;
|
||||
pub use typemap_trait::*;
|
@ -0,0 +1,49 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! impl_typemap {
|
||||
($map:ident, $key:ty) => {
|
||||
pub struct $map($crate::base::TypeMapBase);
|
||||
|
||||
impl $crate::typemap_trait::TypeMapTrait for $map {
|
||||
type Key = $key;
|
||||
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
Self($crate::base::TypeMapBase::new())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn insert<T: $crate::typemap_trait::TypedKeyTrait<Self::Key>>(
|
||||
&mut self,
|
||||
value: T::Value,
|
||||
) {
|
||||
let mto = value.into_mto();
|
||||
self.0.insert::<T>(mto);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get<T: $crate::typemap_trait::TypedKeyTrait<Self::Key>>(&self) -> Option<&T::Value> {
|
||||
self.0.get::<T>().and_then(|v| v.downcast_ref())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut<T: $crate::typemap_trait::TypedKeyTrait<Self::Key>>(
|
||||
&mut self,
|
||||
) -> Option<&mut T::Value> {
|
||||
self.0.get_mut::<T>().and_then(|v| v.downcast_mut())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remove<T: $crate::typemap_trait::TypedKeyTrait<Self::Key>>(
|
||||
&mut self,
|
||||
) -> Option<T::Value> {
|
||||
self.0.remove::<T>().and_then(|v| v.downcast())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn contains_key<T: $crate::typemap_trait::TypedKeyTrait<Self::Key>>(&self) -> bool {
|
||||
self.0.contains_key::<T>()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
use crate::{CloneTypeMap, TypeMap, TypeMapKey, TypeMapTrait};
|
||||
|
||||
pub struct TestStructKey;
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TestStruct {
|
||||
a: u64,
|
||||
b: String,
|
||||
}
|
||||
|
||||
impl Default for TestStruct {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
a: 46,
|
||||
b: String::from("Hello World"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeMapKey for TestStructKey {
|
||||
type Value = TestStruct;
|
||||
}
|
||||
|
||||
pub struct TestStruct2Key;
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TestStruct2 {
|
||||
c: i64,
|
||||
d: bool,
|
||||
}
|
||||
|
||||
impl Default for TestStruct2 {
|
||||
fn default() -> Self {
|
||||
Self { c: 12, d: true }
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeMapKey for TestStruct2Key {
|
||||
type Value = TestStruct2;
|
||||
}
|
||||
|
||||
pub struct NoCloneStruct;
|
||||
|
||||
impl TypeMapKey for NoCloneStruct {
|
||||
type Value = NoCloneStruct;
|
||||
}
|
||||
|
||||
pub struct NotInsertedKey;
|
||||
|
||||
impl TypeMapKey for NotInsertedKey {
|
||||
type Value = ();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_creates_any_maps() {
|
||||
let mut map = TypeMap::new();
|
||||
map.insert::<NoCloneStruct>(NoCloneStruct);
|
||||
map.insert::<TestStructKey>(TestStruct::default());
|
||||
map.insert::<TestStruct2Key>(TestStruct2::default());
|
||||
assert!(map.contains_key::<NoCloneStruct>());
|
||||
assert!(map.contains_key::<TestStructKey>());
|
||||
assert!(map.contains_key::<TestStruct2Key>());
|
||||
assert_eq!(map.contains_key::<NotInsertedKey>(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_creates_clonable_maps() {
|
||||
let mut map = CloneTypeMap::new();
|
||||
map.insert::<TestStructKey>(TestStruct::default());
|
||||
map.insert::<TestStruct2Key>(TestStruct2::default());
|
||||
assert!(map.contains_key::<TestStructKey>());
|
||||
assert!(map.contains_key::<TestStruct2Key>());
|
||||
assert_eq!(map.contains_key::<NotInsertedKey>(), false);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
use crate::base::TypeMapBase;
|
||||
use crate::{impl_typemap, TypeMapKey, TypedKeyMto, TypedKeyTrait};
|
||||
use multi_trait_object::{create_object, MultitraitObject, RawClone, TryClone};
|
||||
|
||||
pub struct CloneTypeMapKey;
|
||||
|
||||
impl<T> TypedKeyTrait<CloneTypeMapKey> for T
|
||||
where
|
||||
T: TypeMapKey,
|
||||
<T as TypeMapKey>::Value: TypedKeyMto<CloneTypeMapKey> + Clone,
|
||||
{
|
||||
type Value = T::Value;
|
||||
}
|
||||
|
||||
impl<T: 'static + Clone> TypedKeyMto<CloneTypeMapKey> for T {
|
||||
fn into_mto(self) -> MultitraitObject {
|
||||
create_object!(self, dyn RawClone)
|
||||
}
|
||||
}
|
||||
|
||||
impl_typemap!(CloneTypeMap, CloneTypeMapKey);
|
||||
|
||||
impl Clone for CloneTypeMap {
|
||||
fn clone(&self) -> Self {
|
||||
let map = self
|
||||
.0
|
||||
.0
|
||||
.iter()
|
||||
.map(|(t, o)| (t.clone(), o.try_clone().unwrap()))
|
||||
.collect();
|
||||
CloneTypeMap(TypeMapBase(map))
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
mod clone_typemap;
|
||||
mod typemap;
|
||||
|
||||
pub use clone_typemap::*;
|
||||
pub use typemap::*;
|
@ -0,0 +1,22 @@
|
||||
use crate::{impl_typemap, TypeMapKey, TypedKeyMto, TypedKeyTrait};
|
||||
use multi_trait_object::{create_object, MultitraitObject};
|
||||
use std::any::Any;
|
||||
|
||||
#[derive(Eq, PartialEq, Hash)]
|
||||
pub struct AnyTypeMapKey;
|
||||
|
||||
impl<T> TypedKeyTrait<AnyTypeMapKey> for T
|
||||
where
|
||||
T: TypeMapKey,
|
||||
<T as TypeMapKey>::Value: Any,
|
||||
{
|
||||
type Value = T::Value;
|
||||
}
|
||||
|
||||
impl<T: 'static> TypedKeyMto<AnyTypeMapKey> for T {
|
||||
fn into_mto(self) -> MultitraitObject {
|
||||
create_object!(self, dyn Any)
|
||||
}
|
||||
}
|
||||
|
||||
impl_typemap!(TypeMap, AnyTypeMapKey);
|
@ -0,0 +1,44 @@
|
||||
use multi_trait_object::MultitraitObject;
|
||||
use std::any::Any;
|
||||
|
||||
/// A trait that allows using the object implementing it
|
||||
/// to be used as a type key.
|
||||
pub trait TypeMapKey: 'static {
|
||||
type Value: Any;
|
||||
}
|
||||
|
||||
/// A trait used for restricting values inserted in a type map
|
||||
/// using type checking
|
||||
pub trait TypedKeyTrait<T>: 'static {
|
||||
type Value: TypedKeyMto<T>;
|
||||
}
|
||||
|
||||
/// A trait used to create a multitrait-object from a given
|
||||
/// value with the given guaranteed trait implementations
|
||||
pub trait TypedKeyMto<T> {
|
||||
fn into_mto(self) -> MultitraitObject;
|
||||
}
|
||||
|
||||
/// A trait implemented by all typemaps that provides
|
||||
/// all basic typemap functions
|
||||
pub trait TypeMapTrait {
|
||||
type Key;
|
||||
|
||||
/// Creates a new typemap
|
||||
fn new() -> Self;
|
||||
|
||||
/// Inserts a value into the typemap with the given key
|
||||
fn insert<T: TypedKeyTrait<Self::Key>>(&mut self, value: T::Value);
|
||||
|
||||
/// Returns a reference to a value from the type map with the given provided key
|
||||
fn get<T: TypedKeyTrait<Self::Key>>(&self) -> Option<&T::Value>;
|
||||
|
||||
/// Returns a mutable reference to a value from the type map with the given provided key
|
||||
fn get_mut<T: TypedKeyTrait<Self::Key>>(&mut self) -> Option<&mut T::Value>;
|
||||
|
||||
/// Removes a value from the map for the given key
|
||||
fn remove<T: TypedKeyTrait<Self::Key>>(&mut self) -> Option<T::Value>;
|
||||
|
||||
/// Returns if the map contains a given key
|
||||
fn contains_key<T: TypedKeyTrait<Self::Key>>(&self) -> bool;
|
||||
}
|
Loading…
Reference in New Issue