fayalite 0.2.0

Hardware Description Language embedded in Rust, using FIRRTL's semantics
Documentation
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use hashbrown::HashMap;
use std::{
    any::{Any, TypeId},
    hash::{BuildHasher, Hasher},
    ptr::NonNull,
    sync::RwLock,
};

struct TypeIdHasher(u64);

// assumes TypeId has at least 64 bits that is a good hash
impl Hasher for TypeIdHasher {
    #[inline(always)]
    fn finish(&self) -> u64 {
        self.0
    }

    #[inline(always)]
    fn write(&mut self, bytes: &[u8]) {
        for &byte in bytes {
            self.write_u8(byte);
        }
    }

    #[inline(always)]
    fn write_u8(&mut self, i: u8) {
        self.0 = self.0.rotate_left(8);
        self.0 ^= i as u64;
    }

    #[inline(always)]
    fn write_u16(&mut self, i: u16) {
        self.0 = self.0.rotate_left(16);
        self.0 ^= i as u64;
    }

    #[inline(always)]
    fn write_u32(&mut self, i: u32) {
        self.0 = self.0.rotate_left(32);
        self.0 ^= i as u64;
    }

    #[inline(always)]
    fn write_u64(&mut self, i: u64) {
        self.0 ^= i;
    }

    #[inline(always)]
    fn write_u128(&mut self, i: u128) {
        self.write_u64(i as u64);
        self.write_u64((i >> 64) as u64);
    }

    #[inline(always)]
    fn write_usize(&mut self, i: usize) {
        match usize::BITS {
            128 => self.write_u128(i as u128),
            64 => self.write_u64(i as u64),
            32 => self.write_u32(i as u32),
            16 => self.write_u16(i as u16),
            _ => self.write(&i.to_ne_bytes()),
        }
    }
}

struct TypeIdBuildHasher;

impl BuildHasher for TypeIdBuildHasher {
    type Hasher = TypeIdHasher;

    fn build_hasher(&self) -> Self::Hasher {
        TypeIdHasher(0)
    }
}

struct Value(NonNull<dyn Any + Send + Sync>);

impl Value {
    unsafe fn get_transmute_lifetime<'b>(&self) -> &'b (dyn Any + Send + Sync) {
        unsafe { &*self.0.as_ptr() }
    }
    fn new(v: Box<dyn Any + Send + Sync>) -> Self {
        unsafe { Self(NonNull::new_unchecked(Box::into_raw(v))) }
    }
}

unsafe impl Send for Value {}
unsafe impl Sync for Value {}

impl Drop for Value {
    fn drop(&mut self) {
        unsafe { std::ptr::drop_in_place(self.0.as_ptr()) }
    }
}

pub struct TypeIdMap(RwLock<HashMap<TypeId, Value, TypeIdBuildHasher>>);

impl TypeIdMap {
    pub const fn new() -> Self {
        Self(RwLock::new(HashMap::with_hasher(TypeIdBuildHasher)))
    }
    #[cold]
    unsafe fn insert_slow(
        &self,
        type_id: TypeId,
        make: fn() -> Box<dyn Any + Sync + Send>,
    ) -> &(dyn Any + Sync + Send) {
        let value = Value::new(make());
        let mut write_guard = self.0.write().unwrap();
        unsafe {
            write_guard
                .entry(type_id)
                .or_insert(value)
                .get_transmute_lifetime()
        }
    }
    pub fn get_or_insert_default<T: Sized + Any + Send + Sync + Default>(&self) -> &T {
        let type_id = TypeId::of::<T>();
        let read_guard = self.0.read().unwrap();
        let retval = read_guard
            .get(&type_id)
            .map(|v| unsafe { Value::get_transmute_lifetime(v) });
        drop(read_guard);
        let retval = match retval {
            Some(retval) => retval,
            None => unsafe { self.insert_slow(type_id, move || Box::new(T::default())) },
        };
        unsafe { &*(retval as *const dyn Any as *const T) }
    }
}

impl Default for TypeIdMap {
    fn default() -> Self {
        Self::new()
    }
}