use std::sync::{Arc, RwLock};
use sim_kernel::{Cx, Error, Object, ObjectCompat, Result, Value};
use crate::standard_mutate_capability;
#[sim_citizen_derive::non_citizen(
reason = "mutable cell handle; reconstruct from the current value plus mutation policy",
kind = "handle",
descriptor = "core/Expr"
)]
#[derive(Clone)]
pub struct Cell {
value: Arc<RwLock<Value>>,
}
impl Cell {
pub fn new(value: Value) -> Self {
Self {
value: Arc::new(RwLock::new(value)),
}
}
pub fn get(&self) -> Result<Value> {
Ok(self
.value
.read()
.map_err(|_| Error::PoisonedLock("mutation cell"))?
.clone())
}
pub fn set(&self, cx: &mut Cx, value: Value) -> Result<()> {
cx.require(&standard_mutate_capability())?;
*self
.value
.write()
.map_err(|_| Error::PoisonedLock("mutation cell"))? = value;
Ok(())
}
}
impl Object for Cell {
fn display(&self, _cx: &mut Cx) -> Result<String> {
Ok("#<mutation-cell>".to_owned())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ObjectCompat for Cell {}
#[sim_citizen_derive::non_citizen(
reason = "mutable box handle; reconstruct from the current value plus mutation policy",
kind = "handle",
descriptor = "core/Expr"
)]
#[derive(Clone)]
pub struct MutableBox {
cell: Cell,
}
impl MutableBox {
pub fn new(value: Value) -> Self {
Self {
cell: Cell::new(value),
}
}
pub fn get(&self) -> Result<Value> {
self.cell.get()
}
pub fn set(&self, cx: &mut Cx, value: Value) -> Result<()> {
self.cell.set(cx, value)
}
}
impl Object for MutableBox {
fn display(&self, _cx: &mut Cx) -> Result<String> {
Ok("#<mutation-box>".to_owned())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ObjectCompat for MutableBox {}
pub fn cell_value(cx: &mut Cx, value: Value) -> Result<Value> {
cx.factory().opaque(Arc::new(Cell::new(value)))
}
pub fn mutable_box_value(cx: &mut Cx, value: Value) -> Result<Value> {
cx.factory().opaque(Arc::new(MutableBox::new(value)))
}