use std::sync::{Arc, RwLock};
use tan::{context::Context, error::Error, expr::Expr, util::module_util::require_module};
pub fn buffer_new(args: &[Expr]) -> Result<Expr, Error> {
let [length] = args else {
return Err(Error::invalid_arguments("requires `length` argument", None));
};
let Some(length) = length.as_int() else {
return Err(Error::invalid_arguments(
&format!("length=`{length}` is not Int"),
length.range(),
));
};
let length = length as usize;
let buf: Vec<u8> = vec![0; length];
Ok(Expr::Buffer(length, Arc::new(RwLock::new(buf))))
}
pub fn buffer_put(args: &[Expr]) -> Result<Expr, Error> {
let [buffer, index, value] = args else {
return Err(Error::invalid_arguments(
"requires `index` and `value` arguments",
None,
));
};
let Some((length, mut buffer)) = buffer.as_buffer_mut() else {
return Err(Error::invalid_arguments(
&format!("buffer=`{buffer}` is not a Buffer"),
buffer.range(),
));
};
let Some(i) = index.as_int() else {
return Err(Error::invalid_arguments(
&format!("index=`{index}` is not Int"),
index.range(),
));
};
if i < 0 {
return Err(Error::invalid_arguments(
&format!("buffer index=`{i}` cannot be negative"),
index.range(),
));
}
let i = i as usize;
if i >= length {
return Err(Error::invalid_arguments(
&format!("buffer index=`{i}` must be less than the buffer length=`{length}`"),
index.range(),
));
}
let Some(value) = value.as_u8() else {
return Err(Error::invalid_arguments(
&format!("value=`{value}` is not U8"),
value.range(),
));
};
buffer[i] = value;
Ok(Expr::None)
}
pub fn setup_lib_buffer(context: &mut Context) {
let module = require_module("prelude", context);
module.insert_invocable("Buffer", Expr::foreign_func(&buffer_new));
module.insert_invocable("put$$Buffer$$Int$$U8", Expr::foreign_func(&buffer_put));
}