use std::vec::Vec;
use crate::encoding::Binary;
use crate::errors::{StdError, StdResult};
#[cfg(feature = "iterator")]
use crate::iterator::{Order, KV};
use crate::memory::{alloc, build_region, consume_region, Region};
use crate::serde::from_slice;
use crate::traits::{Api, Querier, QuerierResult, ReadonlyStorage, Storage};
use crate::types::{CanonicalAddr, HumanAddr};
const CANONICAL_ADDRESS_BUFFER_LENGTH: usize = 32;
const HUMAN_ADDRESS_BUFFER_LENGTH: usize = 90;
extern "C" {
fn db_read(key: u32) -> u32;
fn db_write(key: u32, value: u32);
fn db_remove(key: u32);
#[cfg(feature = "iterator")]
fn db_scan(start_ptr: u32, end_ptr: u32, order: i32) -> u32;
#[cfg(feature = "iterator")]
fn db_next(iterator_id: u32) -> u32;
fn canonicalize_address(source: u32, destination: u32) -> u32;
fn humanize_address(source: u32, destination: u32) -> u32;
fn query_chain(request: u32) -> u32;
}
pub struct ExternalStorage {}
impl ExternalStorage {
pub fn new() -> ExternalStorage {
ExternalStorage {}
}
}
impl ReadonlyStorage for ExternalStorage {
fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
let key = build_region(key);
let key_ptr = &*key as *const Region as u32;
let read = unsafe { db_read(key_ptr) };
if read == 0 {
return None;
}
let value_ptr = read as *mut Region;
let data = unsafe { consume_region(value_ptr) };
Some(data)
}
#[cfg(feature = "iterator")]
fn range(
&self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> Box<dyn Iterator<Item = KV>> {
let start = start.map(|s| build_region(s));
let start_ptr = match start {
Some(reg) => &*reg as *const Region as u32,
None => 0,
};
let end = end.map(|e| build_region(e));
let end_ptr = match end {
Some(reg) => &*reg as *const Region as u32,
None => 0,
};
let order = order as i32;
let iterator_id = unsafe { db_scan(start_ptr, end_ptr, order) };
let iter = ExternalIterator { iterator_id };
Box::new(iter)
}
}
impl Storage for ExternalStorage {
fn set(&mut self, key: &[u8], value: &[u8]) {
let key = build_region(key);
let key_ptr = &*key as *const Region as u32;
let mut value = build_region(value);
let value_ptr = &mut *value as *mut Region as u32;
unsafe { db_write(key_ptr, value_ptr) };
}
fn remove(&mut self, key: &[u8]) {
let key = build_region(key);
let key_ptr = &*key as *const Region as u32;
unsafe { db_remove(key_ptr) };
}
}
#[cfg(feature = "iterator")]
struct ExternalIterator {
iterator_id: u32,
}
#[cfg(feature = "iterator")]
impl Iterator for ExternalIterator {
type Item = KV;
fn next(&mut self) -> Option<Self::Item> {
let next_result = unsafe { db_next(self.iterator_id) };
let kv_region_ptr = next_result as *mut Region;
let mut kv = unsafe { consume_region(kv_region_ptr) };
let keylen = u32::from_be_bytes([
kv[kv.len() - 4],
kv[kv.len() - 3],
kv[kv.len() - 2],
kv[kv.len() - 1],
]) as usize;
if keylen == 0 {
return None;
}
kv.truncate(kv.len() - 4);
let key = kv.split_off(kv.len() - keylen);
let value = kv;
Some((key, value))
}
}
#[derive(Copy, Clone)]
pub struct ExternalApi {}
impl ExternalApi {
pub fn new() -> ExternalApi {
ExternalApi {}
}
}
impl Api for ExternalApi {
fn canonical_address(&self, human: &HumanAddr) -> StdResult<CanonicalAddr> {
let send = build_region(human.as_str().as_bytes());
let send_ptr = &*send as *const Region as u32;
let canon = alloc(CANONICAL_ADDRESS_BUFFER_LENGTH);
let result = unsafe { canonicalize_address(send_ptr, canon as u32) };
if result != 0 {
let error = unsafe { consume_string_region_written_by_vm(result as *mut Region) };
return Err(StdError::generic_err(format!(
"canonicalize_address errored: {}",
error
)));
}
let out = unsafe { consume_region(canon) };
Ok(CanonicalAddr(Binary(out)))
}
fn human_address(&self, canonical: &CanonicalAddr) -> StdResult<HumanAddr> {
let send = build_region(canonical.as_slice());
let send_ptr = &*send as *const Region as u32;
let human = alloc(HUMAN_ADDRESS_BUFFER_LENGTH);
let result = unsafe { humanize_address(send_ptr, human as u32) };
if result != 0 {
let error = unsafe { consume_string_region_written_by_vm(result as *mut Region) };
return Err(StdError::generic_err(format!(
"humanize_address errored: {}",
error
)));
}
let address = unsafe { consume_string_region_written_by_vm(human) };
Ok(address.into())
}
}
unsafe fn consume_string_region_written_by_vm(from: *mut Region) -> String {
let data = consume_region(from);
String::from_utf8_unchecked(data)
}
pub struct ExternalQuerier {}
impl ExternalQuerier {
pub fn new() -> ExternalQuerier {
ExternalQuerier {}
}
}
impl Querier for ExternalQuerier {
fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
let req = build_region(bin_request);
let request_ptr = &*req as *const Region as u32;
let response_ptr = unsafe { query_chain(request_ptr) };
let response = unsafe { consume_region(response_ptr as *mut Region) };
from_slice(&response).unwrap_or_else(|err| Ok(Err(err)))
}
}