use std::cell::{Cell, Ref, RefCell};
use crate::StackIdx;
use crate::value::LuaValue;
#[derive(Debug, Clone)]
pub enum UpValState {
Open {
thread_id: usize,
idx: StackIdx,
},
Closed(LuaValue),
}
#[derive(Debug)]
pub struct UpVal {
open_thread_id: Cell<i64>,
open_idx: Cell<u32>,
closed_value: RefCell<LuaValue>,
pub state: RefCell<UpValState>,
}
const CLOSED_TAG: i64 = -1;
impl UpVal {
pub fn open(thread_id: usize, idx: StackIdx) -> Self {
UpVal {
open_thread_id: Cell::new(thread_id as i64),
open_idx: Cell::new(idx.0),
closed_value: RefCell::new(LuaValue::Nil),
state: RefCell::new(UpValState::Open { thread_id, idx }),
}
}
pub fn closed(v: LuaValue) -> Self {
UpVal {
open_thread_id: Cell::new(CLOSED_TAG),
open_idx: Cell::new(0),
closed_value: RefCell::new(v.clone()),
state: RefCell::new(UpValState::Closed(v)),
}
}
pub fn slot(&self) -> Ref<'_, UpValState> { self.state.borrow() }
pub fn is_open(&self) -> bool { self.open_thread_id.get() >= 0 }
pub fn is_closed(&self) -> bool { self.open_thread_id.get() < 0 }
#[inline(always)]
pub fn try_open_payload(&self) -> Option<(usize, StackIdx)> {
let tid = self.open_thread_id.get();
if tid < 0 {
None
} else {
Some((tid as usize, StackIdx(self.open_idx.get())))
}
}
#[inline(always)]
pub fn closed_value(&self) -> Ref<'_, LuaValue> { self.closed_value.borrow() }
pub fn close_with(&self, v: LuaValue) {
self.open_thread_id.set(CLOSED_TAG);
self.open_idx.set(0);
*self.closed_value.borrow_mut() = v.clone();
*self.state.borrow_mut() = UpValState::Closed(v);
}
pub fn set_closed_value(&self, v: LuaValue) {
self.open_thread_id.set(CLOSED_TAG);
self.open_idx.set(0);
*self.closed_value.borrow_mut() = v.clone();
*self.state.borrow_mut() = UpValState::Closed(v);
}
pub fn try_closed_value(&self) -> Option<std::cell::Ref<'_, LuaValue>> {
if self.is_closed() {
self.closed_value.try_borrow().ok()
} else {
None
}
}
}