use crate::{Environment, eval::apply::eval_apply, impl_native_object, is_invalid_symbol, value::Value};
impl_native_object! {
rust_type: std::sync::mpsc::Receiver<Value>,
type_name_const: MPSC_RECEIVER_TYPE_NAME,
type_name_str: "MpscReceiver",
with_fn: {
name: with_mpsc_receiver,
error_prefix: "ksl::builtin::channel"
},
drop_fn: {
name: drop_receiver,
func_name: "DropReceiver",
error_prefix: "ksl::builtin::channel"
}
}
impl_native_object! {
rust_type: std::sync::mpsc::Sender<Value>,
type_name_const: MPSC_SENDER_TYPE_NAME,
type_name_str: "MpscSender",
with_fn: {
name: with_mpsc_sender,
error_prefix: "ksl::builtin::channel"
},
drop_fn: {
name: drop_sender,
func_name: "DropSender",
error_prefix: "ksl::builtin::channel"
}
}
pub(crate) fn open_channel(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
if let [rx_val, tx_val] = args {
match (rx_val, tx_val) {
(Value::Symbol(rx_sym), Value::Symbol(tx_sym)) => {
if is_invalid_symbol(rx_sym) || is_invalid_symbol(tx_sym) {
Err(std::sync::Arc::from(format!(
concat!(
"Error[ksl::builtin::OpenChannel]: ",
"Rebinding of symbol `{}` or `{}` is not permitted."
),
rx_sym, tx_sym
)))
} else {
let (tx, rx) = std::sync::mpsc::channel::<Value>();
let rx_obj = Value::NativeObject(
MPSC_RECEIVER_TYPE_NAME.clone(),
std::sync::Arc::new(parking_lot::Mutex::new(rx)),
);
let tx_obj = Value::NativeObject(
MPSC_SENDER_TYPE_NAME.clone(),
std::sync::Arc::new(parking_lot::Mutex::new(tx)),
);
env.store
.write()
.insert(rx_sym.clone(), std::sync::Arc::new(rx_obj));
env.store
.write()
.insert(tx_sym.clone(), std::sync::Arc::new(tx_obj));
Ok(Value::Unit)
}
}
(Value::Symbol(_), e) => Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::OpenChannel]: Sender must be a symbol, got `{}`.",
e
))),
(e, _) => Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::OpenChannel]: Receiver must be a symbol, got `{}`.",
e
))),
}
} else {
Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::OpenChannel]: Expected 2 parameters, but {} were passed.",
args.len()
)))
}
}
pub(crate) fn receive_value(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
if let [rx_obj] = args {
let rx_val = eval_apply(rx_obj, env.clone())?;
with_mpsc_receiver(&rx_val, |rx| match rx.recv() {
Ok(val) => Ok(val),
Err(e) => Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::ReceiveValue]: Failed to receive value with `{}`.",
e
))),
})
} else {
Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::ReceiveValue]: Expected 1 parameter, but {} were passed.",
args.len()
)))
}
}
pub(crate) fn send_value(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
if let [tx_obj, val_obj] = args {
let tx_val = eval_apply(tx_obj, env.clone())?;
let val = eval_apply(val_obj, env)?;
with_mpsc_sender(&tx_val, |tx| match tx.send(val) {
Ok(()) => Ok(Value::Unit),
Err(e) => Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::SendValue]: Failed to send value `{}` with `{}`.",
val_obj, e
))),
})
} else {
Err(std::sync::Arc::from(format!(
"Error[ksl::builtin::SendValue]: Expected 1 parameter, but {} were passed.",
args.len()
)))
}
}