jlrs 0.23.0

jlrs provides bindings to the Julia C API that enable Julia code to be called from Rust and more.
Documentation
use std::time::{Duration, Instant};

use jlrs_sys::{jlrs_gc_safe_enter, jlrs_gc_safe_leave};
use parking_lot::RawRwLock;

use crate::memory::get_tls;

/// See [`parking_lot::RawRwLock`] for more information.
pub struct RawGcSafeRwLock {
    inner: RawRwLock,
}

unsafe impl lock_api::RawRwLock for RawGcSafeRwLock {
    const INIT: Self = RawGcSafeRwLock {
        inner: RawRwLock::INIT,
    };

    type GuardMarker = <RawRwLock as lock_api::RawRwLock>::GuardMarker;

    #[inline]
    fn lock_shared(&self) {
        unsafe {
            if self.try_lock_shared() {
                return;
            }

            let ptls = get_tls();
            let state = jlrs_gc_safe_enter(ptls);
            self.inner.lock_shared();
            jlrs_gc_safe_leave(ptls, state);
        }
    }

    #[inline]
    fn try_lock_shared(&self) -> bool {
        self.inner.try_lock_shared()
    }

    #[inline]
    unsafe fn unlock_shared(&self) {
        unsafe {
            self.inner.unlock_shared();
        }
    }

    #[inline]
    fn lock_exclusive(&self) {
        unsafe {
            if self.try_lock_exclusive() {
                return;
            }

            let ptls = get_tls();
            let state = jlrs_gc_safe_enter(ptls);
            self.inner.lock_exclusive();
            jlrs_gc_safe_leave(ptls, state);
        }
    }

    #[inline]
    fn try_lock_exclusive(&self) -> bool {
        self.inner.try_lock_exclusive()
    }

    #[inline]
    unsafe fn unlock_exclusive(&self) {
        unsafe {
            self.inner.unlock_exclusive();
        }
    }
}

unsafe impl lock_api::RawRwLockFair for RawGcSafeRwLock {
    #[inline]
    unsafe fn unlock_shared_fair(&self) {
        unsafe { self.inner.unlock_shared_fair() }
    }

    #[inline]
    unsafe fn unlock_exclusive_fair(&self) {
        unsafe { self.inner.unlock_exclusive_fair() }
    }

    #[inline]
    unsafe fn bump_shared(&self) {
        unsafe { self.inner.bump_shared() }
    }

    #[inline]
    unsafe fn bump_exclusive(&self) {
        unsafe { self.inner.bump_exclusive() }
    }
}

unsafe impl lock_api::RawRwLockDowngrade for RawGcSafeRwLock {
    #[inline]
    unsafe fn downgrade(&self) {
        unsafe { self.inner.downgrade() }
    }
}

unsafe impl lock_api::RawRwLockTimed for RawGcSafeRwLock {
    type Duration = Duration;
    type Instant = Instant;

    #[inline]
    fn try_lock_shared_for(&self, timeout: Self::Duration) -> bool {
        self.inner.try_lock_shared_for(timeout)
    }

    #[inline]
    fn try_lock_shared_until(&self, timeout: Self::Instant) -> bool {
        self.inner.try_lock_shared_until(timeout)
    }

    #[inline]
    fn try_lock_exclusive_for(&self, timeout: Duration) -> bool {
        self.inner.try_lock_exclusive_for(timeout)
    }

    #[inline]
    fn try_lock_exclusive_until(&self, timeout: Instant) -> bool {
        self.inner.try_lock_exclusive_until(timeout)
    }
}

unsafe impl lock_api::RawRwLockRecursive for RawGcSafeRwLock {
    #[inline]
    fn lock_shared_recursive(&self) {
        self.inner.lock_shared_recursive()
    }

    #[inline]
    fn try_lock_shared_recursive(&self) -> bool {
        self.inner.try_lock_shared_recursive()
    }
}

unsafe impl lock_api::RawRwLockRecursiveTimed for RawGcSafeRwLock {
    #[inline]
    fn try_lock_shared_recursive_for(&self, timeout: Self::Duration) -> bool {
        self.inner.try_lock_shared_recursive_for(timeout)
    }

    #[inline]
    fn try_lock_shared_recursive_until(&self, timeout: Self::Instant) -> bool {
        self.inner.try_lock_shared_recursive_until(timeout)
    }
}

unsafe impl lock_api::RawRwLockUpgrade for RawGcSafeRwLock {
    #[inline]
    fn lock_upgradable(&self) {
        unsafe {
            if self.try_lock_upgradable() {
                return;
            }

            let ptls = get_tls();
            let state = jlrs_gc_safe_enter(ptls);
            self.inner.lock_upgradable();
            jlrs_gc_safe_leave(ptls, state);
        }
    }

    #[inline]
    fn try_lock_upgradable(&self) -> bool {
        self.inner.try_lock_upgradable()
    }

    #[inline]
    unsafe fn unlock_upgradable(&self) {
        unsafe { self.inner.unlock_upgradable() }
    }

    #[inline]
    unsafe fn upgrade(&self) {
        unsafe {
            if self.try_upgrade() {
                return;
            }

            let ptls = get_tls();
            let state = jlrs_gc_safe_enter(ptls);
            self.inner.upgrade();
            jlrs_gc_safe_leave(ptls, state);
        }
    }

    #[inline]
    unsafe fn try_upgrade(&self) -> bool {
        unsafe { self.inner.try_upgrade() }
    }
}

unsafe impl lock_api::RawRwLockUpgradeFair for RawGcSafeRwLock {
    #[inline]
    unsafe fn unlock_upgradable_fair(&self) {
        unsafe { self.inner.unlock_upgradable_fair() }
    }

    #[inline]
    unsafe fn bump_upgradable(&self) {
        unsafe { self.inner.bump_upgradable() }
    }
}

unsafe impl lock_api::RawRwLockUpgradeDowngrade for RawGcSafeRwLock {
    #[inline]
    unsafe fn downgrade_upgradable(&self) {
        unsafe { self.inner.downgrade_upgradable() }
    }

    #[inline]
    unsafe fn downgrade_to_upgradable(&self) {
        unsafe { self.inner.downgrade_to_upgradable() }
    }
}

unsafe impl lock_api::RawRwLockUpgradeTimed for RawGcSafeRwLock {
    #[inline]
    fn try_lock_upgradable_until(&self, timeout: Instant) -> bool {
        self.inner.try_lock_upgradable_until(timeout)
    }

    #[inline]
    fn try_lock_upgradable_for(&self, timeout: Duration) -> bool {
        self.inner.try_lock_upgradable_for(timeout)
    }

    #[inline]
    unsafe fn try_upgrade_until(&self, timeout: Instant) -> bool {
        unsafe { self.inner.try_upgrade_until(timeout) }
    }

    #[inline]
    unsafe fn try_upgrade_for(&self, timeout: Duration) -> bool {
        unsafe { self.inner.try_upgrade_for(timeout) }
    }
}