use core::mem::ManuallyDrop;
use core::ptr::NonNull;
#[cfg_attr(feature = "std", path = "env/std.rs")]
mod no_std;
use ::rust_alloc::sync::Arc;
use crate::runtime::vm_diagnostics::VmDiagnosticsObj;
use crate::runtime::{RuntimeContext, Unit, VmErrorKind, VmResult};
pub(crate) fn shared<F, T>(c: F) -> VmResult<T>
where
F: FnOnce(&Arc<RuntimeContext>, &Arc<Unit>) -> VmResult<T>,
{
let env = self::no_std::rune_env_get();
let Env {
context: Some(context),
unit: Some(unit),
..
} = env
else {
return VmResult::err(VmErrorKind::MissingInterfaceEnvironment);
};
let context = unsafe { ManuallyDrop::new(Arc::from_raw(context.as_ptr().cast_const())) };
let unit = unsafe { ManuallyDrop::new(Arc::from_raw(unit.as_ptr().cast_const())) };
c(&context, &unit)
}
pub(crate) fn exclusive<F, T>(c: F) -> VmResult<T>
where
F: FnOnce(&Arc<RuntimeContext>, &Arc<Unit>, Option<&mut VmDiagnosticsObj>) -> VmResult<T>,
{
let guard = Guard {
env: self::no_std::rune_env_replace(Env::null()),
};
let Env {
context: Some(context),
unit: Some(unit),
..
} = guard.env
else {
return VmResult::err(VmErrorKind::MissingInterfaceEnvironment);
};
let context = unsafe { ManuallyDrop::new(Arc::from_raw(context.as_ptr().cast_const())) };
let unit = unsafe { ManuallyDrop::new(Arc::from_raw(unit.as_ptr().cast_const())) };
let diagnostics = match guard.env.diagnostics {
Some(mut d) => Some(unsafe { d.as_mut() }),
None => None,
};
c(&context, &unit, diagnostics)
}
pub(crate) struct Guard {
env: Env,
}
impl Guard {
pub(crate) fn new(
context: Arc<RuntimeContext>,
unit: Arc<Unit>,
diagnostics: Option<NonNull<VmDiagnosticsObj>>,
) -> Guard {
let env = unsafe {
self::no_std::rune_env_replace(Env {
context: Some(NonNull::new_unchecked(Arc::into_raw(context).cast_mut())),
unit: Some(NonNull::new_unchecked(Arc::into_raw(unit).cast_mut())),
diagnostics,
})
};
Guard { env }
}
}
impl Drop for Guard {
fn drop(&mut self) {
let old_env = self::no_std::rune_env_replace(self.env);
unsafe {
if let Some(context) = old_env.context {
drop(Arc::from_raw(context.as_ptr().cast_const()));
}
if let Some(unit) = old_env.unit {
drop(Arc::from_raw(unit.as_ptr().cast_const()));
}
}
}
}
#[derive(Debug, Clone, Copy)]
struct Env {
context: Option<NonNull<RuntimeContext>>,
unit: Option<NonNull<Unit>>,
diagnostics: Option<NonNull<VmDiagnosticsObj>>,
}
impl Env {
const fn null() -> Self {
Self {
context: None,
unit: None,
diagnostics: None,
}
}
}