alef 0.83.0

Opinionated polyglot binding generator for Rust libraries
Documentation
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());
}