extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use core::marker::PhantomData;
use crate::backend::{HostStorage, StorageBackend};
use crate::codec::{BytesCodec, Codec32};
use crate::error::Result;
use crate::hashing;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Namespace(pub [u8; 32]);
impl Namespace {
pub const fn new(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
pub struct StorageMap<V: Codec32> {
namespace: Namespace,
_marker: PhantomData<V>,
}
impl<V: Codec32> StorageMap<V> {
pub const fn new(namespace: Namespace) -> Self {
Self {
namespace,
_marker: PhantomData,
}
}
pub fn exists_slot_for(&self, key: &[u8]) -> [u8; 32] {
hashing::derive_slot(&self.namespace.0, &[b"map:exists", key])
}
pub fn value_slot_for(&self, key: &[u8]) -> [u8; 32] {
hashing::derive_slot(&self.namespace.0, &[b"map:value", key])
}
pub fn slots_for_key(&self, key: &[u8]) -> ([u8; 32], [u8; 32]) {
(self.exists_slot_for(key), self.value_slot_for(key))
}
pub fn contains_key_in<B: StorageBackend>(&self, backend: &B, key: &[u8]) -> Result<bool> {
let exists = backend.read_32(&self.exists_slot_for(key))?;
Ok(exists[0] == 1)
}
pub fn get_in<B: StorageBackend>(&self, backend: &B, key: &[u8]) -> Result<Option<V>> {
if !self.contains_key_in(backend, key)? {
return Ok(None);
}
let raw = backend.read_32(&self.value_slot_for(key))?;
Ok(Some(V::decode_32(&raw)?))
}
pub fn insert_in<B: StorageBackend>(
&self,
backend: &mut B,
key: &[u8],
value: &V,
) -> Result<()> {
let mut exists = [0u8; 32];
exists[0] = 1;
backend.write_32(self.exists_slot_for(key), exists)?;
backend.write_32(self.value_slot_for(key), value.encode_32())?;
Ok(())
}
pub fn remove_in<B: StorageBackend>(&self, backend: &mut B, key: &[u8]) -> Result<()> {
backend.write_32(self.exists_slot_for(key), [0u8; 32])?;
backend.write_32(self.value_slot_for(key), [0u8; 32])?;
Ok(())
}
pub fn contains_typed_key_in<B: StorageBackend, K: BytesCodec>(
&self,
backend: &B,
key: &K,
) -> Result<bool> {
let key_bytes = key.encode_bytes();
self.contains_key_in(backend, &key_bytes)
}
pub fn get_typed_key_in<B: StorageBackend, K: BytesCodec>(
&self,
backend: &B,
key: &K,
) -> Result<Option<V>> {
let key_bytes = key.encode_bytes();
self.get_in(backend, &key_bytes)
}
pub fn insert_typed_key_in<B: StorageBackend, K: BytesCodec>(
&self,
backend: &mut B,
key: &K,
value: &V,
) -> Result<()> {
let key_bytes = key.encode_bytes();
self.insert_in(backend, &key_bytes, value)
}
pub fn remove_typed_key_in<B: StorageBackend, K: BytesCodec>(
&self,
backend: &mut B,
key: &K,
) -> Result<()> {
let key_bytes = key.encode_bytes();
self.remove_in(backend, &key_bytes)
}
pub fn contains_key(&self, key: &[u8]) -> Result<bool> {
let host = HostStorage;
self.contains_key_in(&host, key)
}
pub fn get(&self, key: &[u8]) -> Result<Option<V>> {
let host = HostStorage;
self.get_in(&host, key)
}
pub fn insert(&self, key: &[u8], value: &V) -> Result<()> {
let mut host = HostStorage;
self.insert_in(&mut host, key, value)
}
pub fn remove(&self, key: &[u8]) -> Result<()> {
let mut host = HostStorage;
self.remove_in(&mut host, key)
}
pub fn contains_typed_key<K: BytesCodec>(&self, key: &K) -> Result<bool> {
let host = HostStorage;
self.contains_typed_key_in(&host, key)
}
pub fn get_typed_key<K: BytesCodec>(&self, key: &K) -> Result<Option<V>> {
let host = HostStorage;
self.get_typed_key_in(&host, key)
}
pub fn insert_typed_key<K: BytesCodec>(&self, key: &K, value: &V) -> Result<()> {
let mut host = HostStorage;
self.insert_typed_key_in(&mut host, key, value)
}
pub fn remove_typed_key<K: BytesCodec>(&self, key: &K) -> Result<()> {
let mut host = HostStorage;
self.remove_typed_key_in(&mut host, key)
}
}
pub struct StorageVec<V: Codec32> {
namespace: Namespace,
_marker: PhantomData<V>,
}
impl<V: Codec32> StorageVec<V> {
pub const fn new(namespace: Namespace) -> Self {
Self {
namespace,
_marker: PhantomData,
}
}
pub fn len_slot(&self) -> [u8; 32] {
hashing::derive_slot(&self.namespace.0, &[b"vec:len"])
}
pub fn slot_for_index(&self, index: u64) -> [u8; 32] {
let idx = hashing::index_u64(index);
hashing::derive_slot(&self.namespace.0, &[b"vec:elem", &idx])
}
pub fn len_in<B: StorageBackend>(&self, backend: &B) -> Result<u64> {
let raw = backend.read_32(&self.len_slot())?;
<u64 as Codec32>::decode_32(&raw)
}
pub fn is_empty_in<B: StorageBackend>(&self, backend: &B) -> Result<bool> {
Ok(self.len_in(backend)? == 0)
}
pub fn get_in<B: StorageBackend>(&self, backend: &B, index: u64) -> Result<Option<V>> {
let len = self.len_in(backend)?;
if index >= len {
return Ok(None);
}
let raw = backend.read_32(&self.slot_for_index(index))?;
Ok(Some(V::decode_32(&raw)?))
}
pub fn set_in<B: StorageBackend>(
&self,
backend: &mut B,
index: u64,
value: &V,
) -> Result<bool> {
let len = self.len_in(backend)?;
if index >= len {
return Ok(false);
}
backend.write_32(self.slot_for_index(index), value.encode_32())?;
Ok(true)
}
pub fn push_in<B: StorageBackend>(&self, backend: &mut B, value: &V) -> Result<u64> {
let len = self.len_in(backend)?;
backend.write_32(self.slot_for_index(len), value.encode_32())?;
backend.write_32(self.len_slot(), (len + 1).encode_32())?;
Ok(len)
}
pub fn pop_in<B: StorageBackend>(&self, backend: &mut B) -> Result<Option<V>> {
let len = self.len_in(backend)?;
if len == 0 {
return Ok(None);
}
let index = len - 1;
let raw = backend.read_32(&self.slot_for_index(index))?;
backend.write_32(self.len_slot(), index.encode_32())?;
backend.write_32(self.slot_for_index(index), [0u8; 32])?;
Ok(Some(V::decode_32(&raw)?))
}
pub fn clear_in<B: StorageBackend>(&self, backend: &mut B) -> Result<()> {
backend.write_32(self.len_slot(), 0u64.encode_32())
}
pub fn len(&self) -> Result<u64> {
let host = HostStorage;
self.len_in(&host)
}
pub fn get(&self, index: u64) -> Result<Option<V>> {
let host = HostStorage;
self.get_in(&host, index)
}
pub fn set(&self, index: u64, value: &V) -> Result<bool> {
let mut host = HostStorage;
self.set_in(&mut host, index, value)
}
pub fn push(&self, value: &V) -> Result<u64> {
let mut host = HostStorage;
self.push_in(&mut host, value)
}
pub fn pop(&self) -> Result<Option<V>> {
let mut host = HostStorage;
self.pop_in(&mut host)
}
pub fn clear(&self) -> Result<()> {
let mut host = HostStorage;
self.clear_in(&mut host)
}
}
pub struct StorageBlob {
namespace: Namespace,
}
impl StorageBlob {
pub const fn new(namespace: Namespace) -> Self {
Self { namespace }
}
pub fn len_slot(&self) -> [u8; 32] {
hashing::derive_slot(&self.namespace.0, &[b"blob:len"])
}
pub fn slot_for_chunk(&self, index: u64) -> [u8; 32] {
let idx = hashing::index_u64(index);
hashing::derive_slot(&self.namespace.0, &[b"blob:chunk", &idx])
}
pub fn write_in<B: StorageBackend>(&self, backend: &mut B, data: &[u8]) -> Result<()> {
let chunks = if data.is_empty() {
0
} else {
((data.len() - 1) / 32) + 1
};
for i in 0..chunks {
let start = i * 32;
let end = (start + 32).min(data.len());
let mut chunk = [0u8; 32];
chunk[..(end - start)].copy_from_slice(&data[start..end]);
backend.write_32(self.slot_for_chunk(i as u64), chunk)?;
}
backend.write_32(self.len_slot(), (data.len() as u64).encode_32())?;
Ok(())
}
pub fn read_in<B: StorageBackend>(&self, backend: &B) -> Result<Vec<u8>> {
let raw_len = backend.read_32(&self.len_slot())?;
let len = <u64 as Codec32>::decode_32(&raw_len)? as usize;
if len == 0 {
return Ok(Vec::new());
}
let chunks = ((len - 1) / 32) + 1;
let mut out = vec![0u8; chunks * 32];
for i in 0..chunks {
let chunk = backend.read_32(&self.slot_for_chunk(i as u64))?;
let start = i * 32;
out[start..start + 32].copy_from_slice(&chunk);
}
out.truncate(len);
Ok(out)
}
pub fn clear_in<B: StorageBackend>(&self, backend: &mut B) -> Result<()> {
backend.write_32(self.len_slot(), 0u64.encode_32())
}
pub fn put_in<B: StorageBackend, T: BytesCodec>(
&self,
backend: &mut B,
value: &T,
) -> Result<()> {
self.write_in(backend, &value.encode_bytes())
}
pub fn get_in<B: StorageBackend, T: BytesCodec>(&self, backend: &B) -> Result<T> {
let raw = self.read_in(backend)?;
T::decode_bytes(&raw)
}
pub fn write(&self, data: &[u8]) -> Result<()> {
let mut host = HostStorage;
self.write_in(&mut host, data)
}
pub fn read(&self) -> Result<Vec<u8>> {
let host = HostStorage;
self.read_in(&host)
}
pub fn put<T: BytesCodec>(&self, value: &T) -> Result<()> {
let mut host = HostStorage;
self.put_in(&mut host, value)
}
pub fn get<T: BytesCodec>(&self) -> Result<T> {
let host = HostStorage;
self.get_in(&host)
}
pub fn clear(&self) -> Result<()> {
let mut host = HostStorage;
self.clear_in(&mut host)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::MemoryStorage;
const NS_MAP: Namespace = Namespace([1u8; 32]);
const NS_VEC: Namespace = Namespace([2u8; 32]);
const NS_BLOB: Namespace = Namespace([3u8; 32]);
#[test]
fn map_roundtrip() {
let mut mem = MemoryStorage::new();
let map = StorageMap::<u64>::new(NS_MAP);
assert_eq!(map.get_in(&mem, b"alice").unwrap(), None);
map.insert_in(&mut mem, b"alice", &42).unwrap();
assert_eq!(map.get_in(&mem, b"alice").unwrap(), Some(42));
map.remove_in(&mut mem, b"alice").unwrap();
assert_eq!(map.get_in(&mem, b"alice").unwrap(), None);
}
#[test]
fn vec_roundtrip() {
let mut mem = MemoryStorage::new();
let list = StorageVec::<u64>::new(NS_VEC);
assert_eq!(list.len_in(&mem).unwrap(), 0);
list.push_in(&mut mem, &7).unwrap();
list.push_in(&mut mem, &9).unwrap();
assert_eq!(list.len_in(&mem).unwrap(), 2);
assert_eq!(list.get_in(&mem, 1).unwrap(), Some(9));
assert_eq!(list.pop_in(&mut mem).unwrap(), Some(9));
assert_eq!(list.len_in(&mem).unwrap(), 1);
}
#[test]
fn blob_roundtrip() {
let mut mem = MemoryStorage::new();
let blob = StorageBlob::new(NS_BLOB);
let data = b"hello storage blob".to_vec();
blob.write_in(&mut mem, &data).unwrap();
assert_eq!(blob.read_in(&mem).unwrap(), data);
}
#[test]
fn map_typed_keys_roundtrip() {
let mut mem = MemoryStorage::new();
let map = StorageMap::<u64>::new(NS_MAP);
let key = [7u8; 32];
map.insert_typed_key_in(&mut mem, &key, &88).unwrap();
assert_eq!(map.get_typed_key_in(&mem, &key).unwrap(), Some(88));
map.remove_typed_key_in(&mut mem, &key).unwrap();
assert_eq!(map.get_typed_key_in(&mem, &key).unwrap(), None);
}
}