type AlefHandle = u64;
const HANDLE_INDEX_MASK: u64 = u32::MAX as u64;
#[derive(Debug)]
enum HandleError {
InvalidZero,
UnknownSlot,
StaleGeneration,
WrongType,
RegistryPoisoned,
HandleBusy,
AliasedHandle,
}
impl std::fmt::Display for HandleError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let message = match self {
Self::InvalidZero => "zero is not a valid handle",
Self::UnknownSlot => "handle refers to an unknown slot",
Self::StaleGeneration => "handle generation is stale",
Self::WrongType => "handle has the wrong type",
Self::RegistryPoisoned => "handle registry lock is poisoned",
Self::HandleBusy => "handle is currently in use",
Self::AliasedHandle => "the same handle was passed more than once",
};
formatter.write_str(message)
}
}
type ErasedHandleValue = std::sync::Arc<std::sync::Mutex<Box<dyn std::any::Any + Send>>>;
struct HandleSlot {
generation: u32,
value: Option<ErasedHandleValue>,
}
#[derive(Default)]
struct HandleRegistry {
slots: Vec<HandleSlot>,
}
impl HandleRegistry {
fn insert<T: std::any::Any + Send>(&mut self, value: T) -> AlefHandle {
let entry = std::sync::Arc::new(std::sync::Mutex::new(Box::new(value) as Box<dyn std::any::Any + Send>));
if let Some((index, slot)) = self.slots.iter_mut().enumerate().find(|(_, slot)| slot.value.is_none()) {
slot.value = Some(entry);
return encode_handle(index, slot.generation);
}
self.slots.push(HandleSlot {
generation: 1,
value: Some(entry),
});
encode_handle(self.slots.len() - 1, 1)
}
fn get(&self, handle: AlefHandle) -> Result<ErasedHandleValue, HandleError> {
let (index, generation) = decode_handle(handle)?;
let slot = self.slots.get(index).ok_or(HandleError::UnknownSlot)?;
if slot.generation != generation {
return Err(HandleError::StaleGeneration);
}
slot.value.clone().ok_or(HandleError::StaleGeneration)
}
fn remove<T: std::any::Any + Send>(&mut self, handle: AlefHandle) -> Result<(), HandleError> {
drop(self.take::<T>(handle)?);
Ok(())
}
fn take<T: std::any::Any + Send>(&mut self, handle: AlefHandle) -> Result<T, HandleError> {
let (index, generation) = decode_handle(handle)?;
let slot = self.slots.get_mut(index).ok_or(HandleError::UnknownSlot)?;
if slot.generation != generation {
return Err(HandleError::StaleGeneration);
}
let value = slot.value.as_ref().ok_or(HandleError::StaleGeneration)?;
let guard = value.lock().map_err(|_| HandleError::RegistryPoisoned)?;
if !guard.is::<T>() {
return Err(HandleError::WrongType);
}
drop(guard);
let value = slot.value.take().ok_or(HandleError::StaleGeneration)?;
let mutex = std::sync::Arc::try_unwrap(value).map_err(|value| {
slot.value = Some(value);
HandleError::HandleBusy
})?;
slot.generation = next_generation(slot.generation);
let boxed = mutex.into_inner().map_err(|_| HandleError::RegistryPoisoned)?;
boxed.downcast::<T>().map(|value| *value).map_err(|_| HandleError::WrongType)
}
}
static HANDLE_REGISTRY: std::sync::OnceLock<std::sync::Mutex<HandleRegistry>> = std::sync::OnceLock::new();
fn handle_registry() -> &'static std::sync::Mutex<HandleRegistry> {
HANDLE_REGISTRY.get_or_init(|| std::sync::Mutex::new(HandleRegistry::default()))
}
fn insert_handle<T: std::any::Any + Send>(value: T) -> Result<AlefHandle, HandleError> {
let mut registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
Ok(registry.insert(value))
}
struct SerializedHandle<T: 'static> {
json: String,
marker: std::marker::PhantomData<fn() -> T>,
}
fn insert_serialized_handle<T: serde::Serialize + 'static>(value: &T) -> Result<AlefHandle, String> {
let json = serde_json::to_string(value).map_err(|error| error.to_string())?;
insert_handle(SerializedHandle::<T> {
json,
marker: std::marker::PhantomData,
})
.map_err(|error| error.to_string())
}
fn with_handle<T: std::any::Any + Send, R>(
handle: AlefHandle,
operation: impl FnOnce(&T) -> R,
) -> Result<R, HandleError> {
let value = {
let registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
registry.get(handle)?
};
let guard = value.lock().map_err(|_| HandleError::RegistryPoisoned)?;
let typed = guard.downcast_ref::<T>().ok_or(HandleError::WrongType)?;
Ok(operation(typed))
}
struct HandleRequest {
handle: AlefHandle,
expected_type: std::any::TypeId,
}
fn acquire_handles(requests: &[HandleRequest]) -> Result<Vec<(AlefHandle, ErasedHandleValue)>, HandleError> {
let mut ordered = requests.iter().collect::<Vec<_>>();
ordered.sort_by_key(|request| request.handle);
if ordered.windows(2).any(|pair| pair[0].handle == pair[1].handle) {
return Err(HandleError::AliasedHandle);
}
let registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
let mut values = Vec::with_capacity(ordered.len());
for request in ordered {
let value = registry.get(request.handle)?;
let guard = value.lock().map_err(|_| HandleError::RegistryPoisoned)?;
if guard.as_ref().type_id() != request.expected_type {
return Err(HandleError::WrongType);
}
drop(guard);
values.push((request.handle, value));
}
Ok(values)
}
fn locked_handle_ptr<T: std::any::Any + Send>(
guards: &mut [(AlefHandle, std::sync::MutexGuard<'_, Box<dyn std::any::Any + Send>>)],
handle: AlefHandle,
) -> Result<*mut T, HandleError> {
let (_, guard) = guards.iter_mut().find(|(candidate, _)| *candidate == handle).ok_or(HandleError::UnknownSlot)?;
guard.downcast_mut::<T>().map(|value| value as *mut T).ok_or(HandleError::WrongType)
}
fn with_handle_mut<T: std::any::Any + Send, R>(
handle: AlefHandle,
operation: impl FnOnce(&mut T) -> R,
) -> Result<R, HandleError> {
let value = {
let registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
registry.get(handle)?
};
let mut guard = value.lock().map_err(|_| HandleError::RegistryPoisoned)?;
let typed = guard.downcast_mut::<T>().ok_or(HandleError::WrongType)?;
Ok(operation(typed))
}
fn remove_handle<T: std::any::Any + Send>(handle: AlefHandle) -> Result<(), HandleError> {
let mut registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
registry.remove::<T>(handle)
}
fn take_handle<T: std::any::Any + Send>(handle: AlefHandle) -> Result<T, HandleError> {
let mut registry = handle_registry().lock().map_err(|_| HandleError::RegistryPoisoned)?;
registry.take::<T>(handle)
}
fn encode_handle(index: usize, generation: u32) -> AlefHandle {
((generation as u64) << 32) | ((index as u64) + 1)
}
fn decode_handle(handle: AlefHandle) -> Result<(usize, u32), HandleError> {
if handle == 0 {
return Err(HandleError::InvalidZero);
}
let encoded_index = handle & HANDLE_INDEX_MASK;
if encoded_index == 0 {
return Err(HandleError::UnknownSlot);
}
Ok(((encoded_index - 1) as usize, (handle >> 32) as u32))
}
fn next_generation(generation: u32) -> u32 {
let next = generation.wrapping_add(1);
if next == 0 { 1 } else { next }
}
fn set_handle_error(error: &HandleError) {
set_last_error(ALEF_INVALID_HANDLE_ERROR, &error.to_string());
}