use luna_core::runtime::value::Value;
use luna_core::vm::error::LuaError;
use luna_core::vm::exec::Vm;
pub(crate) fn bind_keys_argv(vm: &mut Vm, keys: &[&[u8]], args: &[&[u8]]) {
let keys_t = build_byte_array(vm, keys);
let _ = vm.set_global("KEYS", Value::Table(keys_t));
let argv_t = build_byte_array(vm, args);
let _ = vm.set_global("ARGV", Value::Table(argv_t));
}
pub(crate) fn install_redis_table(vm: &mut Vm) {
let call_fn = vm.native(crate::dispatch::redis_call);
let pcall_fn = vm.native(crate::dispatch::redis_pcall);
let status_fn = vm.native(redis_status_reply);
let error_fn = vm.native(redis_error_reply);
let sha1_fn = vm.native(redis_sha1hex);
let log_fn = vm.native(redis_log);
let replicate_fn = vm.native(redis_replicate_commands);
let t = vm.table_of([
("call", call_fn),
("pcall", pcall_fn),
("status_reply", status_fn),
("error_reply", error_fn),
("sha1hex", sha1_fn),
("log", log_fn),
("replicate_commands", replicate_fn),
]);
let _ = vm.set_global("redis", Value::Table(t));
}
fn build_byte_array(vm: &mut Vm, items: &[&[u8]]) -> luna_core::runtime::heap::Gc<luna_core::runtime::Table> {
let mut entries: Vec<(i64, Value)> = Vec::with_capacity(items.len());
for (i, bytes) in items.iter().enumerate() {
let s = Value::Str(vm.heap.intern(bytes));
entries.push(((i + 1) as i64, s));
}
let mut b = vm.new_table();
for (k, v) in entries {
b = b.with(k, v);
}
b.build()
}
fn redis_status_reply(vm: &mut Vm, fs: u32, nargs: u32) -> Result<u32, LuaError> {
let msg = first_arg_as_str_or(vm, fs, nargs, b"OK");
let s = Value::Str(vm.heap.intern(&msg));
let t = vm.new_table().with("ok", s).build();
Ok(vm.nat_return(fs, &[Value::Table(t)]))
}
fn redis_error_reply(vm: &mut Vm, fs: u32, nargs: u32) -> Result<u32, LuaError> {
let msg = first_arg_as_str_or(vm, fs, nargs, b"ERR");
let s = Value::Str(vm.heap.intern(&msg));
let t = vm.new_table().with("err", s).build();
Ok(vm.nat_return(fs, &[Value::Table(t)]))
}
fn redis_sha1hex(vm: &mut Vm, fs: u32, nargs: u32) -> Result<u32, LuaError> {
let bytes = if nargs >= 1 {
match vm.nat_arg(fs, nargs, 0) {
Value::Str(s) => s.as_bytes().to_vec(),
Value::Int(n) => n.to_string().into_bytes(),
Value::Float(f) => format!("{f}").into_bytes(),
_ => Vec::new(),
}
} else {
Vec::new()
};
let digest = crate::sha1::sha1(&bytes);
let hex = crate::sha1::hex(&digest);
let v = Value::Str(vm.heap.intern(&hex));
Ok(vm.nat_return(fs, &[v]))
}
fn redis_log(_vm: &mut Vm, _fs: u32, _nargs: u32) -> Result<u32, LuaError> {
Ok(0)
}
fn redis_replicate_commands(_vm: &mut Vm, _fs: u32, _nargs: u32) -> Result<u32, LuaError> {
Ok(0)
}
fn first_arg_as_str_or(vm: &mut Vm, fs: u32, nargs: u32, default_msg: &[u8]) -> Vec<u8> {
if nargs == 0 {
return default_msg.to_vec();
}
match vm.nat_arg(fs, nargs, 0) {
Value::Str(s) => s.as_bytes().to_vec(),
Value::Int(n) => n.to_string().into_bytes(),
Value::Float(f) => format!("{f}").into_bytes(),
_ => default_msg.to_vec(),
}
}