use std::cell::UnsafeCell;
use std::sync::{Arc, RwLock};
use crate::runtime::Value;
use crate::version::LuaVersion;
use crate::vm::error::LuaError;
use crate::vm::exec::Vm;
use crate::vm::host_roots::{HostRootStale, HostRootTicket};
use crate::vm::userdata_trait::LuaUserdata;
pub struct SendVm {
inner: Arc<UnsafeCell<Vm>>,
lock: Arc<RwLock<()>>,
}
unsafe impl Send for SendVm {}
impl SendVm {
pub fn new(version: LuaVersion) -> Self {
let vm = Vm::new_minimal(version);
#[allow(clippy::arc_with_non_send_sync)]
let inner = Arc::new(UnsafeCell::new(vm));
Self {
inner,
lock: Arc::new(RwLock::new(())),
}
}
pub fn from_vm(vm: Vm) -> Self {
#[allow(clippy::arc_with_non_send_sync)]
let inner = Arc::new(UnsafeCell::new(vm));
Self {
inner,
lock: Arc::new(RwLock::new(())),
}
}
pub fn open_base(&self) {
self.with_vm_mut(|vm| vm.open_base());
}
pub fn open_math(&self) {
self.with_vm_mut(|vm| vm.open_math());
}
pub fn open_string(&self) {
self.with_vm_mut(|vm| vm.open_string());
}
pub fn open_table(&self) {
self.with_vm_mut(|vm| vm.open_table());
}
pub fn open_coroutine(&self) {
self.with_vm_mut(|vm| vm.open_coroutine());
}
pub fn eval(&self, src: &str) -> Result<Vec<Value>, LuaError> {
self.with_vm_mut(|vm| vm.eval(src))
}
pub fn call_value(&self, f: Value, args: &[Value]) -> Result<Vec<Value>, LuaError> {
self.with_vm_mut(|vm| vm.call_value(f, args))
}
pub fn set_global<V: crate::vm::IntoValue>(&self, name: &str, v: V) -> Result<(), LuaError> {
self.with_vm_mut(|vm| vm.set_global(name, v))
}
pub fn get_global(&self, name: &str) -> Value {
self.with_vm_mut(|vm| {
let key = Value::Str(vm.heap.intern(name.as_bytes()));
unsafe { (*vm.globals().as_ptr()).get(key) }
})
}
pub fn intern_str(&self, s: &str) -> crate::runtime::Gc<crate::runtime::LuaStr> {
self.with_vm_mut(|vm| vm.intern_str(s))
}
pub fn set_userdata<T: LuaUserdata>(&self, name: &str, value: T) -> Result<(), LuaError> {
self.with_vm_mut(|vm| vm.set_userdata(name, value))
}
pub fn pin_host(&self, v: Value) -> HostRootTicket {
self.with_vm_mut(|vm| vm.pin_host(v))
}
pub fn read_host(&self, t: HostRootTicket) -> Option<Value> {
self.with_vm_mut(|vm| vm.read_host(t))
}
pub fn unpin(&self, t: HostRootTicket) -> Result<(), HostRootStale> {
self.with_vm_mut(|vm| vm.unpin(t))
}
pub fn trace_dispatched_count(&self) -> u64 {
self.with_vm_mut(|vm| vm.trace_dispatched_count())
}
#[doc(hidden)]
pub fn __j_e_handle_arc_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
pub fn with_vm<R>(&self, f: impl FnOnce(&Vm) -> R) -> R {
let _guard = self.lock.write().unwrap_or_else(|e| e.into_inner());
let vm: &Vm = unsafe { &*self.inner.get() };
f(vm)
}
#[inline]
fn with_vm_mut<R>(&self, f: impl FnOnce(&mut Vm) -> R) -> R {
let _guard = self.lock.write().unwrap_or_else(|e| {
e.into_inner()
});
let vm: &mut Vm = unsafe { &mut *self.inner.get() };
f(vm)
}
}
impl Clone for SendVm {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
lock: Arc::clone(&self.lock),
}
}
}
impl std::fmt::Debug for SendVm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SendVm")
.field("handles", &Arc::strong_count(&self.inner))
.finish_non_exhaustive()
}
}