use std::time::Duration;
use crate::{BAD_HANDLE, ERR, OK, arg, with};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_set(h: u32, kp: *const u8, kl: u32, vp: *const u8, vl: u32) -> i32 {
let (key, value) = unsafe { (arg(kp, kl), arg(vp, vl)) };
with(h, BAD_HANDLE, |inst| match inst.store.set(key, value) {
Ok(_) => {
inst.log_frame(&[b"SET", key, value]);
OK
}
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_set_ttl(
h: u32,
kp: *const u8,
kl: u32,
vp: *const u8,
vl: u32,
ttl_ms: f64,
) -> i32 {
let (key, value) = unsafe { (arg(kp, kl), arg(vp, vl)) };
let ms = if ttl_ms > 0.0 { ttl_ms as u64 } else { 0 };
with(h, BAD_HANDLE, |inst| {
match inst.store.set_with_ttl(key, value, Duration::from_millis(ms)) {
Ok(_) => {
let deadline = kevy_store::now_unix_ms().saturating_add(ms);
inst.log_frame(&[b"SET", key, value]);
inst.log_frame(&[b"PEXPIREAT", key, deadline.to_string().as_bytes()]);
OK
}
Err(e) => inst.fail_kevy(&e),
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_get(h: u32, kp: *const u8, kl: u32) -> i32 {
let key = unsafe { arg(kp, kl) };
with(h, BAD_HANDLE, |inst| match inst.store.get(key) {
Ok(Some(v)) => {
inst.out = v;
1
}
Ok(None) => 0,
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_del(h: u32, kp: *const u8, kl: u32) -> i32 {
let key = unsafe { arg(kp, kl) };
with(h, BAD_HANDLE, |inst| match inst.store.del(&[key]) {
Ok(n) => {
if n > 0 {
inst.log_frame(&[b"DEL", key]);
}
n as i32
}
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_exists(h: u32, kp: *const u8, kl: u32) -> i32 {
let key = unsafe { arg(kp, kl) };
with(h, BAD_HANDLE, |inst| match inst.store.exists(&[key]) {
Ok(n) => n as i32,
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_expire(h: u32, kp: *const u8, kl: u32, ttl_ms: f64) -> i32 {
let key = unsafe { arg(kp, kl) };
let ms = if ttl_ms > 0.0 { ttl_ms as u64 } else { 0 };
with(h, BAD_HANDLE, |inst| match inst.store.expire(key, Duration::from_millis(ms)) {
Ok(true) => {
let deadline = kevy_store::now_unix_ms().saturating_add(ms);
inst.log_frame(&[b"PEXPIREAT", key, deadline.to_string().as_bytes()]);
1
}
Ok(false) => 0,
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_persist(h: u32, kp: *const u8, kl: u32) -> i32 {
let key = unsafe { arg(kp, kl) };
with(h, BAD_HANDLE, |inst| match inst.store.persist(key) {
Ok(true) => {
inst.log_frame(&[b"PERSIST", key]);
1
}
Ok(false) => 0,
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_pttl(h: u32, kp: *const u8, kl: u32) -> f64 {
let key = unsafe { arg(kp, kl) };
with(h, f64::NAN, |inst| inst.store.ttl_ms(key) as f64)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_incrby(h: u32, kp: *const u8, kl: u32, delta: f64) -> i32 {
let key = unsafe { arg(kp, kl) };
let d = delta as i64;
with(h, BAD_HANDLE, |inst| match inst.store.incr_by(key, d) {
Ok(n) => {
inst.log_frame(&[b"INCRBY", key, d.to_string().as_bytes()]);
inst.put_out(n.to_string().as_bytes());
OK
}
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kevy_dbsize(h: u32) -> f64 {
with(h, f64::NAN, |inst| inst.store.dbsize() as f64)
}
#[unsafe(no_mangle)]
pub extern "C" fn kevy_flushall(h: u32) -> i32 {
with(h, BAD_HANDLE, |inst| match inst.store.flushall() {
Ok(()) => {
inst.log_frame(&[b"FLUSHALL"]);
OK
}
Err(e) => inst.fail_kevy(&e),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_keys(h: u32, pp: *const u8, pl: u32, limit: u32) -> i32 {
let pat = unsafe { arg(pp, pl) };
let pattern = (!pat.is_empty()).then_some(pat);
let limit = (limit > 0).then_some(limit as usize);
with(h, BAD_HANDLE, |inst| {
let keys = inst.store.collect_keys(pattern, limit);
if keys.len() > i32::MAX as usize {
return ERR;
}
inst.out.clear();
for k in &keys {
inst.out.extend_from_slice(&(k.len() as u32).to_le_bytes());
inst.out.extend_from_slice(k);
}
keys.len() as i32
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kevy_mget(h: u32, kp: *const u8, kl: u32, count: u32) -> i32 {
let buf = unsafe { arg(kp, kl) };
if count > i32::MAX as u32 {
return ERR;
}
with(h, BAD_HANDLE, |inst| {
inst.out.clear();
let mut off = 0usize;
for _ in 0..count {
let Some(hdr) = off.checked_add(4).and_then(|e| buf.get(off..e)) else {
return ERR;
};
let len = u32::from_le_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]) as usize;
off += 4;
let Some(key) = off.checked_add(len).and_then(|e| buf.get(off..e)) else {
return ERR;
};
off += len;
match inst.store.get(key) {
Ok(Some(v)) => {
inst.out.extend_from_slice(&(v.len() as u32).to_le_bytes());
inst.out.extend_from_slice(&v);
}
Ok(None) => inst.out.extend_from_slice(&u32::MAX.to_le_bytes()),
Err(e) => return inst.fail_kevy(&e),
}
}
count as i32
})
}