extern crate alloc;
use alloc::vec::Vec;
use fuel_indexer_lib::{
graphql::MAX_FOREIGN_KEY_LIST_FIELDS,
utils::{deserialize, serialize},
WasmIndexerError,
};
use fuel_indexer_schema::{
join::{JoinMetadata, RawQuery},
FtColumn,
};
use fuel_indexer_types::{ffi::*, scalar::UID};
pub use bincode;
pub use hex::FromHex;
pub use sha2::{Digest, Sha256};
pub use std::collections::{HashMap, HashSet};
pub use crate::find::{Field, Filter, ManyFilter, OptionField, SingleFilter};
extern "C" {
fn ff_get_object(type_id: i64, ptr: *const u8, len: *mut u8) -> *mut u8;
fn ff_find_many(type_id: i64, ptr: *const u8, len: *mut u8) -> *mut u8;
fn ff_log_data(ptr: *const u8, len: u32, log_level: u32);
fn ff_put_object(type_id: i64, ptr: *const u8, len: u32);
fn ff_put_many_to_many_record(ptr: *const u8, len: u32);
fn ff_early_exit(err_code: u32);
}
pub struct Logger;
impl Logger {
pub fn error(log: &str) {
unsafe { ff_log_data(log.as_ptr(), log.len() as u32, LOG_LEVEL_ERROR) }
}
pub fn warn(log: &str) {
unsafe { ff_log_data(log.as_ptr(), log.len() as u32, LOG_LEVEL_WARN) }
}
pub fn info(log: &str) {
unsafe { ff_log_data(log.as_ptr(), log.len() as u32, LOG_LEVEL_INFO) }
}
pub fn debug(log: &str) {
unsafe { ff_log_data(log.as_ptr(), log.len() as u32, LOG_LEVEL_DEBUG) }
}
pub fn trace(log: &str) {
unsafe { ff_log_data(log.as_ptr(), log.len() as u32, LOG_LEVEL_TRACE) }
}
}
pub trait Entity<'a>: Sized + PartialEq + Eq + std::fmt::Debug {
const TYPE_ID: i64;
const JOIN_METADATA: Option<[Option<JoinMetadata<'a>>; MAX_FOREIGN_KEY_LIST_FIELDS]>;
fn from_row(vec: Vec<FtColumn>) -> Self;
fn to_row(&self) -> Vec<FtColumn>;
fn type_id(&self) -> i64 {
Self::TYPE_ID
}
fn save_many_to_many(&self) {
if let Some(meta) = Self::JOIN_METADATA {
let items = meta.iter().filter_map(|x| x.clone()).collect::<Vec<_>>();
let row = self.to_row();
let queries = items
.iter()
.map(|item| RawQuery::from_metadata(item, &row))
.filter(|query| !query.is_empty())
.collect::<Vec<_>>();
let bytes = serialize(&queries);
unsafe {
ff_put_many_to_many_record(bytes.as_ptr(), bytes.len() as u32);
}
}
}
fn load(id: UID) -> Option<Self> {
Self::load_unsafe(id)
}
fn load_unsafe(id: UID) -> Option<Self> {
unsafe {
let buff = if let Ok(bytes) = bincode::serialize(&id.to_string()) {
bytes
} else {
early_exit(WasmIndexerError::SerializationError);
};
let mut bufflen = (buff.len() as u32).to_le_bytes();
let ptr = ff_get_object(Self::TYPE_ID, buff.as_ptr(), bufflen.as_mut_ptr());
if !ptr.is_null() {
let len = u32::from_le_bytes(bufflen) as usize;
let bytes = Vec::from_raw_parts(ptr, len, len);
match deserialize(&bytes) {
Ok(vec) => Some(Self::from_row(vec)),
Err(_) => {
early_exit(WasmIndexerError::DeserializationError);
}
};
}
None
}
}
fn find(filter: impl Into<SingleFilter<Self>>) -> Option<Self> {
let result = Self::find_many(filter.into());
result.into_iter().next()
}
fn find_many(filter: impl Into<ManyFilter<Self>>) -> Vec<Self> {
unsafe {
let filter: ManyFilter<Self> = filter.into();
let buff = bincode::serialize(&filter.to_string())
.expect("Failed to serialize query");
let mut bufflen = (buff.len() as u32).to_le_bytes();
let ptr = ff_find_many(Self::TYPE_ID, buff.as_ptr(), bufflen.as_mut_ptr());
if !ptr.is_null() {
let len = u32::from_le_bytes(bufflen) as usize;
let bytes = Vec::from_raw_parts(ptr, len, len);
let data: Vec<Vec<u8>> =
deserialize(&bytes).expect("Failed to deserialize data");
data.iter()
.map(|x| {
Self::from_row(
deserialize(x).expect("Failed to deserialize data"),
)
})
.collect()
} else {
vec![]
}
}
}
fn save(&self) {
self.save_unsafe()
}
fn save_unsafe(&self) {
unsafe {
let buf = serialize(&self.to_row());
ff_put_object(Self::TYPE_ID, buf.as_ptr(), buf.len() as u32);
}
self.save_many_to_many()
}
}
#[no_mangle]
fn alloc_fn(size: u32) -> *const u8 {
let vec = Vec::with_capacity(size as usize);
let ptr = vec.as_ptr();
core::mem::forget(vec);
ptr
}
#[no_mangle]
fn dealloc_fn(ptr: *mut u8, len: usize) {
let _vec = unsafe { Vec::from_raw_parts(ptr, len, len) };
}
#[no_mangle]
pub fn early_exit(err_code: WasmIndexerError) -> ! {
unsafe { ff_early_exit(err_code as u32) }
unreachable!("Expected termination of WASM exetution after a call to ff_early_exit.")
}