use crate::{
native_raw, AccountNumber, DbId, HttpRequest, MicroSeconds, SocketEndpoint, TLSInfo, ToKey,
};
use anyhow::anyhow;
use fracpack::{Pack, Unpack, UnpackOwned};
pub fn write_console_bytes(message: &[u8]) {
unsafe {
if let Some(first) = message.first() {
native_raw::writeConsole(first, message.len() as u32);
}
}
}
pub fn write_console(message: &str) {
write_console_bytes(message.as_bytes());
}
pub fn abort_message_bytes(message: &[u8]) -> ! {
unsafe {
if let Some(first) = message.first() {
native_raw::abortMessage(first, message.len() as u32)
} else {
native_raw::abortMessage(std::ptr::null(), 0)
}
}
}
pub fn abort_message(message: &str) -> ! {
abort_message_bytes(message.as_bytes());
}
pub fn check(condition: bool, message: &str) {
if !condition {
abort_message_bytes(message.as_bytes());
}
}
pub fn check_some<T>(opt_value: Option<T>, message: &str) -> T {
if opt_value.is_none() {
abort_message_bytes(message.as_bytes());
}
opt_value.unwrap()
}
pub fn check_none<T>(opt_value: Option<T>, message: &str) {
if opt_value.is_some() {
abort_message_bytes(message.as_bytes());
}
}
pub fn get_result_bytes(size: u32) -> Vec<u8> {
let mut result = Vec::with_capacity(size as usize);
if size > 0 {
unsafe {
let actual_size = native_raw::getResult(result.as_mut_ptr(), size, 0);
result.set_len(std::cmp::min(size, actual_size) as usize);
}
}
result
}
pub fn get_key_bytes() -> Vec<u8> {
unsafe {
let size = native_raw::getKey(std::ptr::null_mut(), 0);
let mut result = Vec::with_capacity(size as usize);
if size > 0 {
native_raw::getKey(result.as_mut_ptr(), size);
result.set_len(size as usize);
}
result
}
}
pub fn get_current_action_bytes() -> Vec<u8> {
let size;
unsafe {
size = native_raw::getCurrentAction();
};
get_result_bytes(size)
}
pub fn get_current_action() -> crate::Action {
let bytes = get_current_action_bytes();
<crate::Action>::unpacked(&bytes[..]).unwrap() }
pub fn with_current_action<R, F: Fn(crate::SharedAction) -> R>(f: F) -> R {
let bytes = get_current_action_bytes();
let act = <crate::SharedAction>::unpacked(&bytes[..]).unwrap(); f(act)
}
pub fn set_retval<T: Pack>(val: &T) {
let bytes = val.packed();
unsafe { native_raw::setRetval(bytes.as_ptr(), bytes.len() as u32) };
}
pub fn get_optional_result_bytes(size: u32) -> Option<Vec<u8>> {
if size < u32::MAX {
Some(get_result_bytes(size))
} else {
None
}
}
#[derive(Debug)]
pub struct KvHandle(native_raw::KvHandle);
pub use native_raw::KvMode;
impl KvHandle {
pub fn new(db: DbId, prefix: &[u8], mode: KvMode) -> KvHandle {
match db {
DbId::Service | DbId::WriteOnly | DbId::BlockLog | DbId::Native => Self::import(
crate::services::db::Wrapper::call().open(db, prefix.to_vec().into(), mode as u8),
),
DbId::Subjective | DbId::Session | DbId::Temporary => Self::import(
crate::services::x_db::Wrapper::call().open(db, prefix.to_vec().into(), mode as u8),
),
_ => KvHandle(unsafe {
native_raw::kvOpen(db, prefix.as_ptr(), prefix.len() as u32, mode)
}),
}
}
pub fn subtree(&self, prefix: &[u8], mode: KvMode) -> KvHandle {
KvHandle(unsafe {
native_raw::kvOpenAt(self.0, prefix.as_ptr(), prefix.len() as u32, mode)
})
}
pub fn import(index: u32) -> KvHandle {
let handles =
Vec::<u32>::unpacked(&get_result_bytes(unsafe { native_raw::importHandles() }))
.unwrap();
KvHandle(native_raw::KvHandle(handles[index as usize]))
}
}
impl Drop for KvHandle {
fn drop(&mut self) {
unsafe { native_raw::kvClose(self.0) }
}
}
pub fn kv_put_bytes(db: &KvHandle, key: &[u8], value: &[u8]) {
unsafe {
native_raw::kvPut(
db.0,
key.as_ptr(),
key.len() as u32,
value.as_ptr(),
value.len() as u32,
)
}
}
pub fn kv_put<K: ToKey, V: Pack>(db: &KvHandle, key: &K, value: &V) {
kv_put_bytes(db, &key.to_key(), &value.packed())
}
pub fn put_sequential_bytes(db: DbId, value: &[u8]) -> u64 {
unsafe { native_raw::putSequential(db, value.as_ptr(), value.len() as u32) }
}
pub fn put_sequential<Type: Pack, V: Pack>(
db: DbId,
service: AccountNumber,
ty: &Type,
value: &V,
) -> u64 {
put_sequential_bytes(db, &(service, Some(ty), Some(value)).packed())
}
pub fn kv_remove_bytes(db: &KvHandle, key: &[u8]) {
unsafe { native_raw::kvRemove(db.0, key.as_ptr(), key.len() as u32) }
}
pub fn kv_remove<K: ToKey>(db: &KvHandle, key: &K) {
kv_remove_bytes(db, &key.to_key())
}
pub fn kv_get_bytes(db: &KvHandle, key: &[u8]) -> Option<Vec<u8>> {
let size = unsafe { native_raw::kvGet(db.0, key.as_ptr(), key.len() as u32) };
get_optional_result_bytes(size)
}
pub fn kv_get<V: UnpackOwned, K: ToKey>(
db: &KvHandle,
key: &K,
) -> Result<Option<V>, fracpack::Error> {
if let Some(v) = kv_get_bytes(db, &key.to_key()) {
Ok(Some(V::unpacked(&v)?))
} else {
Ok(None)
}
}
pub fn kv_greater_equal_bytes(db: &KvHandle, key: &[u8], match_key_size: u32) -> Option<Vec<u8>> {
let size =
unsafe { native_raw::kvGreaterEqual(db.0, key.as_ptr(), key.len() as u32, match_key_size) };
get_optional_result_bytes(size)
}
pub fn kv_greater_equal<K: ToKey, V: UnpackOwned>(
db: &KvHandle,
key: &K,
match_key_size: u32,
) -> Option<V> {
let bytes = kv_greater_equal_bytes(db, &key.to_key(), match_key_size);
bytes.map(|v| V::unpacked(&v[..]).unwrap())
}
pub fn kv_less_than_bytes(db: &KvHandle, key: &[u8], match_key_size: u32) -> Option<Vec<u8>> {
let size =
unsafe { native_raw::kvLessThan(db.0, key.as_ptr(), key.len() as u32, match_key_size) };
get_optional_result_bytes(size)
}
pub fn kv_less_than<K: ToKey, V: UnpackOwned>(
db: &KvHandle,
key: &K,
match_key_size: u32,
) -> Option<V> {
let bytes = kv_less_than_bytes(db, &key.to_key(), match_key_size);
bytes.map(|v| V::unpacked(&v[..]).unwrap())
}
pub fn kv_max_bytes(db: &KvHandle, key: &[u8]) -> Option<Vec<u8>> {
let size = unsafe { native_raw::kvMax(db.0, key.as_ptr(), key.len() as u32) };
get_optional_result_bytes(size)
}
pub fn kv_max<K: ToKey, V: UnpackOwned>(db: &KvHandle, key: &K) -> Option<V> {
let bytes = kv_max_bytes(db, &key.to_key());
bytes.map(|v| V::unpacked(&v[..]).unwrap())
}
pub fn get_sequential_bytes(db_id: DbId, id: u64) -> Option<Vec<u8>> {
let size = unsafe { native_raw::getSequential(db_id, id) };
get_optional_result_bytes(size)
}
pub fn set_max_cpu_time<T: Into<MicroSeconds>>(time: T) {
let time: MicroSeconds = time.into();
let time = (time.value * 1000) as u64;
unsafe { native_raw::setMaxCpuTime(time) }
}
pub use scopeguard;
pub fn checkout_subjective() {
unsafe { native_raw::checkoutSubjective() }
}
pub fn commit_subjective() -> bool {
unsafe { native_raw::commitSubjective() }
}
pub fn abort_subjective() {
unsafe { native_raw::abortSubjective() }
}
#[macro_export]
macro_rules! subjective_tx {
{$($stmt:tt)*} => {
$crate::native::checkout_subjective();
#[allow(unreachable_code)]
let r = loop {
let mut guard = $crate::native::scopeguard::guard((), |_|{
$crate::native::abort_subjective();
});
let result = { $($stmt)* };
$crate::native::scopeguard::ScopeGuard::into_inner(guard);
if $crate::native::commit_subjective() {
break result;
}
};
r
}
}
pub fn socket_open(
req: HttpRequest,
tls: Option<TLSInfo>,
endpoint: Option<SocketEndpoint>,
) -> Result<i32, anyhow::Error> {
let packed = (req, tls, endpoint).packed();
let sock = unsafe { native_raw::socketOpen(packed.as_ptr(), packed.len()) };
if sock >= 0 {
Ok(sock)
} else {
Err(anyhow!("socket_open: {}", -sock))
}
}
pub fn socket_send(fd: i32, data: &[u8]) -> Result<(), anyhow::Error> {
let err = unsafe { native_raw::socketSend(fd, data.as_ptr(), data.len()) };
if err == 0 {
Ok(())
} else {
Err(anyhow!("socket_send: {}", err))
}
}
pub fn socket_set_flags(fd: i32, mask: u32, value: u32) -> Result<(), anyhow::Error> {
let err = unsafe { native_raw::socketSetFlags(fd, mask, value) };
if err == 0 {
Ok(())
} else {
Err(anyhow!("socket_set_flags: {}", err))
}
}