1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//! An ffi-safe equivalent of `std::any::TypeId`.
//!
//! No types coming from different dynamic libraries compare equal.
use std::{
any::TypeId,
hash::{Hash, Hasher},
mem,
sync::atomic::AtomicUsize,
};
use crate::{sabi_types::MaybeCmp, EXECUTABLE_IDENTITY};
///////////////////////////////////////////////////////////////////////////////
/// `extern "C" fn` version of `UTypeId::new`.
///
/// # Example
///
/// ```
/// use abi_stable::std_types::utypeid::new_utypeid;
/// use std::collections::HashMap;
///
/// let hashmap_id = new_utypeid::<HashMap<String, String>>();
/// let vec_id = new_utypeid::<Vec<String>>();
/// let u32_id = new_utypeid::<u32>();
///
/// assert_eq!(hashmap_id, hashmap_id);
/// assert_eq!(vec_id, vec_id);
/// assert_eq!(u32_id, u32_id);
///
/// assert_ne!(vec_id, hashmap_id);
/// assert_ne!(u32_id, hashmap_id);
/// assert_ne!(vec_id, u32_id);
///
/// ```
pub extern "C" fn new_utypeid<T>() -> UTypeId
where
T: 'static,
{
UTypeId::new::<T>()
}
#[doc(hidden)]
pub extern "C" fn some_utypeid<T>() -> MaybeCmp<UTypeId>
where
T: 'static,
{
MaybeCmp::Just(UTypeId::new::<T>())
}
#[doc(hidden)]
#[allow(clippy::missing_const_for_fn)]
pub extern "C" fn no_utypeid() -> MaybeCmp<UTypeId> {
MaybeCmp::Nothing
}
/// An ffi-safe equivalent of `std::any::TypeId` that
/// can compare types across dynamic libraries.
///
/// No `UTypeId` constructed in different dynamic libraries compare equal.
///
/// # Example
///
/// ```
/// use abi_stable::std_types::UTypeId;
///
/// assert_eq!(UTypeId::new::<()>(), UTypeId::new::<()>());
/// assert_eq!(UTypeId::new::<Box<String>>(), UTypeId::new::<Box<String>>());
///
/// assert_ne!(UTypeId::new::<()>(), UTypeId::new::<Vec<()>>());
/// assert_ne!(UTypeId::new::<Box<String>>(), UTypeId::new::<&str>());
/// ```
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Hash, StableAbi)]
pub struct UTypeId {
/// A dummy AtomicUsize used as the identity of the dynamic-library/executable
executable_identity: *const AtomicUsize,
/// An array containing the butes of a TypeId,
/// with `MAX_TYPE_ID_SIZE` bytes of space in case it becomes larger.
type_id_array: [u8; MAX_TYPE_ID_SIZE],
}
unsafe impl Send for UTypeId {}
unsafe impl Sync for UTypeId {}
impl UTypeId {
/// Constructs `UTypeId` from a type that satisfies the `'static` bound.
///
/// # Example
///
/// ```
/// use abi_stable::std_types::UTypeId;
/// use std::collections::HashMap;
///
/// let id = UTypeId::new::<HashMap<String, String>>();
/// # drop(id);
/// ```
#[inline(always)]
pub fn new<T>() -> Self
where
T: 'static,
{
Self {
executable_identity: &EXECUTABLE_IDENTITY,
type_id_array: get_typeid::<T>(),
}
}
}
/////////////////////////////////////////////////////////////////////////////
type TypeIdArray = [u8; mem::size_of::<TypeId>()];
const MAX_TYPE_ID_SIZE: usize = 16;
#[inline(always)]
fn get_typeid<T: 'static>() -> [u8; MAX_TYPE_ID_SIZE] {
let mut hasher = TypeIdHasher {
value: [0; MAX_TYPE_ID_SIZE],
written: 0,
};
TypeId::of::<T>().hash(&mut hasher);
hasher.value
}
#[derive(Default)]
struct TypeIdHasher {
value: [u8; MAX_TYPE_ID_SIZE],
written: usize,
}
impl TypeIdHasher {
#[inline(never)]
#[cold]
fn overflow_msg() -> ! {
eprintln!(
"TypeId requires writing more than {} bytes to the hasher.",
MAX_TYPE_ID_SIZE
);
::std::process::abort();
}
}
impl Hasher for TypeIdHasher {
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
let _: [u8; MAX_TYPE_ID_SIZE - mem::size_of::<TypeId>()];
if bytes.len() == mem::size_of::<TypeId>() {
unsafe {
let into = (&mut self.value) as *mut _ as *mut TypeIdArray;
let from = bytes.as_ptr() as *const TypeIdArray;
*into = *from;
}
self.written = mem::size_of::<TypeId>();
return;
}
let old_pos = self.written;
self.written += bytes.len();
if self.written <= MAX_TYPE_ID_SIZE {
self.value[old_pos..self.written].copy_from_slice(bytes);
} else {
Self::overflow_msg()
}
}
#[inline(always)]
fn finish(&self) -> u64 {
// I'm not gonna call this
0
}
}