//! Threading primitives
use std::{fmt, sync::Arc, thread::{self, sleep}, time::Duration};
use parking_lot::RwLock;
use scheme_rs_macros::bridge;
use crate::{
exceptions::Exception,
gc::{Gc, Trace},
proc::Procedure,
records::{RecordTypeDescriptor, SchemeCompatible, rtd},
value::{Cell, Value},
vectors::Vector,
};
#[derive(Trace)]
pub struct JoinHandle {
values: Cell,
}
impl fmt::Debug for JoinHandle {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl SchemeCompatible for JoinHandle {
fn rtd() -> Arc<RecordTypeDescriptor> {
rtd!(name: "join-handle", sealed: true, opaque: true)
}
}
#[bridge(name = "spawn", lib = "(threads (1))")]
pub fn spawn(thunk: Procedure) -> Result<Vec<Value>, Exception> {
let cell = Gc::new(RwLock::new(Value::undefined()));
let cell_cloned = cell.clone();
thread::spawn(move || {
let mut cell_write = cell_cloned.write();
// TODO: Handle errors
*cell_write = Value::from(thunk.call(&[]).unwrap());
});
Ok(vec![Value::from_rust_type(JoinHandle {
values: Cell(cell),
})])
}
#[bridge(name = "join", lib = "(threads (1))")]
pub fn join(handle: &Value) -> Result<Vec<Value>, Exception> {
let handle = handle.try_to_rust_type::<JoinHandle>()?;
let values = handle.values.get().cast_to_scheme_type::<Vector>().unwrap();
Ok(values.clone_inner_vec())
}
#[bridge(name = "sleep", lib = "(threads (1))")]
pub fn sleep_ms(ms: u64) -> Result<Vec<Value>, Exception> {
sleep(Duration::from_millis(ms));
Ok(Vec::new())
}