use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::HashMap;
#[derive(Debug)]
pub struct VecOwner<T>(Vec<T>);
impl<T> VecOwner<T>
where T: StaticType {
pub fn new() -> Self {
Self(vec![])
}
#[inline]
pub(crate) fn push(&mut self, v: T) -> *const T::Ref {
let ptr = v.ref_ptr();
self.0.push(v);
debug_assert_eq!(
self.0.last().unwrap().ref_ptr(),
ptr,
"Trait promises we're not uphold"
);
ptr
}
pub fn child(&mut self) -> VecChild<'_, T> {
VecChild(self)
}
}
#[derive(Debug)]
pub struct VecChild<'a, T>(&'a mut VecOwner<T>);
impl<'a, T> VecChild<'a, T>
where T: StaticType {
pub fn push(&mut self, v: T) -> &'a T::Ref {
let ptr = self.0.push(v);
unsafe { &*ptr }
}
}
#[derive(Debug)]
pub struct HashMapOwner<K, T>(HashMap<K, T>);
impl<K, T> HashMapOwner<K, T>
where
K: Hash + Eq + Clone,
T: StaticType {
pub fn new() -> Self {
Self(HashMap::new())
}
pub(crate) fn as_ref(&self) -> &HashMap<K, T> {
&self.0
}
#[inline]
pub(crate) fn try_insert(&mut self, key: K, v: T) -> Option<*const T::Ref> {
if self.0.contains_key(&key) {
return None
}
let ptr = v.ref_ptr();
if cfg!(debug_assertions) {
self.0.insert(key.clone(), v);
let v = self.0.get(&key).unwrap();
assert_eq!(ptr, v.ref_ptr(), "Trait promises we're not uphold");
} else {
self.0.insert(key, v);
}
Some(ptr)
}
pub fn child(&mut self) -> HashMapChild<'_, K, T> {
HashMapChild(self)
}
}
#[derive(Debug)]
pub struct HashMapChild<'a, K, T>(&'a mut HashMapOwner<K, T>);
impl<'a, K, T> HashMapChild<'a, K, T>
where
K: Hash + Eq + Clone,
T: StaticType {
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq {
self.0.as_ref().contains_key(k)
}
pub fn try_insert(&mut self, key: K, v: T) -> Option<&'a T::Ref> {
self.0.try_insert(key, v)
.map(|ptr| {
unsafe { &*ptr }
})
}
pub fn insert(&mut self, key: K, v: T) -> &'a T::Ref {
let ptr = self.0.try_insert(key, v).expect("Key already exists");
unsafe { &*ptr }
}
}
pub unsafe trait StaticType {
type Ref: ?Sized;
fn ref_ptr(&self) -> *const Self::Ref;
}
unsafe impl<T: ?Sized> StaticType for Box<T> {
type Ref = T;
#[inline]
fn ref_ptr(&self) -> *const Self::Ref {
&**self
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
#[test]
fn insert_to_vec() {
let mut v = VecOwner::new();
let mut v = v.child();
let s1 = v.push(Box::new(String::from("hey")));
let s2 = v.push(Box::new(String::from("hey 2")));
assert_eq!("hey", s1);
assert_eq!("hey 2", s2);
}
#[test]
#[should_panic]
fn insert_twice() {
let mut files = HashMapOwner::new();
let mut files = files.child();
files.insert("abc", vec![1].into_boxed_slice());
files.insert("abc", vec![1].into_boxed_slice());
}
#[test]
fn test_auto_traits() {
type Basic = Box<usize>;
is_send::<VecOwner<Basic>>();
is_sync::<VecOwner<Basic>>();
is_send::<VecChild<Basic>>();
is_sync::<VecChild<Basic>>();
is_send::<HashMapOwner<Basic, Basic>>();
is_sync::<HashMapOwner<Basic, Basic>>();
is_send::<HashMapChild<Basic, Basic>>();
is_sync::<HashMapChild<Basic, Basic>>();
}
}