#![allow(unsafe_code)]
use super::txn_context::TxnContext;
use crate::engine::EngineResult;
use crate::panic_guard::FfiBoundary;
use crate::runtime::FfiPtr;
fn write_row_ctx(ctx: Option<&mut TxnContext>, table: &str, row: &[u8]) -> EngineResult {
match ctx {
Some(c) => c.session_mut().write_row(table, row),
None => Ok(()),
}
}
fn update_row_ctx(
ctx: Option<&mut TxnContext>,
table: &str,
old: &[u8],
new: &[u8],
) -> EngineResult {
match ctx {
Some(c) => c.session_mut().update_row(table, old, new),
None => Ok(()),
}
}
fn delete_row_ctx(ctx: Option<&mut TxnContext>, table: &str, row: &[u8]) -> EngineResult {
match ctx {
Some(c) => c.session_mut().delete_row(table, row),
None => Ok(()),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_write_row(
ctx: *mut TxnContext,
table: *const u8,
table_len: usize,
row: *const u8,
row_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let table = match unsafe { FfiPtr::bytes_to_str(table, table_len) } {
Ok(t) => t,
Err(e) => return Err(e),
};
let row = unsafe { FfiPtr::slice_const(row, row_len) };
write_row_ctx(unsafe { ctx.as_mut() }, table, row)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_update_row(
ctx: *mut TxnContext,
table: *const u8,
table_len: usize,
old: *const u8,
old_len: usize,
new: *const u8,
new_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let table = match unsafe { FfiPtr::bytes_to_str(table, table_len) } {
Ok(t) => t,
Err(e) => return Err(e),
};
let old = unsafe { FfiPtr::slice_const(old, old_len) };
let new = unsafe { FfiPtr::slice_const(new, new_len) };
update_row_ctx(unsafe { ctx.as_mut() }, table, old, new)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_delete_row(
ctx: *mut TxnContext,
table: *const u8,
table_len: usize,
row: *const u8,
row_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let table = match unsafe { FfiPtr::bytes_to_str(table, table_len) } {
Ok(t) => t,
Err(e) => return Err(e),
};
let row = unsafe { FfiPtr::slice_const(row, row_len) };
delete_row_ctx(unsafe { ctx.as_mut() }, table, row)
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hton::TxnSession;
#[derive(Default)]
struct RecordingTxn {
writes: u32,
updates: u32,
deletes: u32,
}
impl TxnSession for RecordingTxn {
fn commit(&mut self, _all: bool) -> EngineResult {
Ok(())
}
fn rollback(&mut self, _all: bool) -> EngineResult {
Ok(())
}
fn write_row(&mut self, _table: &str, _row: &[u8]) -> EngineResult {
self.writes += 1;
Ok(())
}
fn update_row(&mut self, _table: &str, _old: &[u8], _new: &[u8]) -> EngineResult {
self.updates += 1;
Ok(())
}
fn delete_row(&mut self, _table: &str, _row: &[u8]) -> EngineResult {
self.deletes += 1;
Ok(())
}
}
#[test]
fn null_ctx_row_staging_is_a_noop_success() {
assert_eq!(write_row_ctx(None, "t", b"row"), Ok(()));
assert_eq!(update_row_ctx(None, "t", b"old", b"new"), Ok(()));
assert_eq!(delete_row_ctx(None, "t", b"row"), Ok(()));
}
#[test]
fn some_ctx_row_staging_dispatches_each_variant() {
let mut ctx = TxnContext::new(Box::new(RecordingTxn::default()));
assert_eq!(write_row_ctx(Some(&mut ctx), "t", b"row"), Ok(()));
assert_eq!(update_row_ctx(Some(&mut ctx), "t", b"old", b"new"), Ok(()));
assert_eq!(delete_row_ctx(Some(&mut ctx), "t", b"row"), Ok(()));
}
}