use super::{Erase, GlobalStorage, Storage, StorageB8, StorageGuard, StorageGuardMut, StorageType};
use crate::crypto;
use alloc::{
string::{String, ToString},
vec::Vec,
};
use alloy_primitives::{U256, U8};
use core::cell::OnceCell;
pub struct StorageBytes {
root: U256,
base: OnceCell<U256>,
}
impl StorageType for StorageBytes {
type Wraps<'a> = StorageGuard<'a, StorageBytes> where Self: 'a;
type WrapsMut<'a> = StorageGuardMut<'a, StorageBytes> where Self: 'a;
unsafe fn new(root: U256, offset: u8) -> Self {
debug_assert!(offset == 0);
Self {
root,
base: OnceCell::new(),
}
}
fn load<'s>(self) -> Self::Wraps<'s> {
StorageGuard::new(self)
}
fn load_mut<'s>(self) -> Self::WrapsMut<'s> {
StorageGuardMut::new(self)
}
}
impl StorageBytes {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
let word = Storage::get_word(self.root);
let slot: &[u8] = word.as_ref();
if slot[31] & 1 == 0 {
return (slot[31] / 2) as usize;
}
let word: U256 = word.into();
let len = word / U256::from(2);
len.try_into().unwrap()
}
pub unsafe fn set_len(&mut self, len: usize) {
let old = self.len();
if (old < 32) == (len < 32) {
return self.write_len(len);
}
if (len < 32) && (old > 32) {
let word = Storage::get_word(*self.base());
Storage::set_word(self.root, word);
return self.write_len(len);
}
let mut word = Storage::get_word(self.root);
word[31] = 0; Storage::set_word(*self.base(), word);
self.write_len(len)
}
unsafe fn write_len(&mut self, len: usize) {
if len < 32 {
Storage::set_uint(self.root, 31, U8::from(len * 2));
} else {
Storage::set_word(self.root, U256::from(len * 2 + 1).into())
}
}
pub fn push(&mut self, b: u8) {
let index = self.len();
let value = U8::from(b);
macro_rules! assign {
($slot:expr) => {
unsafe {
Storage::set_uint($slot, index % 32, value); self.write_len(index + 1);
}
};
}
if index < 31 {
return assign!(self.root);
}
if index == 31 {
let word = Storage::get_word(self.root);
unsafe { Storage::set_word(*self.base(), word) };
}
let slot = self.base() + U256::from(index / 32);
assign!(slot);
}
pub fn pop(&mut self) -> Option<u8> {
let len = self.len();
if len == 0 {
return None;
}
let index = len - 1;
let clean = index % 32 == 0;
let byte = self.get(index)?;
let clear = |slot| unsafe { Storage::clear_word(slot) };
if len == 32 {
let word = Storage::get_word(*self.base());
unsafe { Storage::set_word(self.root, word) };
clear(*self.base());
}
if len > 32 && clean {
clear(self.index_slot(len - 1).0);
}
if len < 32 {
unsafe { Storage::set_byte(self.root, index, 0) };
}
unsafe { self.write_len(index) };
Some(byte)
}
pub fn get(&self, index: impl TryInto<usize>) -> Option<u8> {
let index = index.try_into().ok()?;
if index >= self.len() {
return None;
}
unsafe { Some(self.get_unchecked(index)) }
}
pub fn get_mut(&mut self, index: impl TryInto<usize>) -> Option<StorageGuardMut<StorageB8>> {
let index = index.try_into().ok()?;
if index >= self.len() {
return None;
}
let (slot, offset) = self.index_slot(index);
let value = unsafe { StorageB8::new(slot, offset) };
Some(StorageGuardMut::new(value))
}
pub unsafe fn get_unchecked(&self, index: usize) -> u8 {
let (slot, offset) = self.index_slot(index);
unsafe { Storage::get_byte(slot, offset.into()) }
}
pub fn get_bytes(&self) -> Vec<u8> {
let len = self.len();
let mut bytes = Vec::with_capacity(len);
for i in 0..len {
let byte = unsafe { self.get_unchecked(i) };
bytes.push(byte);
}
bytes
}
pub fn set_bytes(&mut self, bytes: impl AsRef<[u8]>) {
self.erase();
self.extend(bytes.as_ref());
}
fn index_slot(&self, index: usize) -> (U256, u8) {
let slot = match self.len() {
33.. => self.base() + U256::from(index / 32),
_ => self.root,
};
(slot, (index % 32) as u8)
}
fn base(&self) -> &U256 {
self.base
.get_or_init(|| crypto::keccak(self.root.to_be_bytes::<32>()).into())
}
}
impl Erase for StorageBytes {
fn erase(&mut self) {
let mut len = self.len() as isize;
if len > 31 {
while len > 0 {
let slot = self.index_slot(len as usize - 1).0;
unsafe { Storage::clear_word(slot) };
len -= 32;
}
}
unsafe { Storage::clear_word(self.root) };
}
}
impl Extend<u8> for StorageBytes {
fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
for elem in iter {
self.push(elem);
}
}
}
impl<'a> Extend<&'a u8> for StorageBytes {
fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
for elem in iter {
self.push(*elem);
}
}
}
pub struct StorageString(pub StorageBytes);
impl StorageType for StorageString {
type Wraps<'a> = StorageGuard<'a, StorageString> where Self: 'a;
type WrapsMut<'a> = StorageGuardMut<'a, StorageString> where Self: 'a;
unsafe fn new(slot: U256, offset: u8) -> Self {
Self(StorageBytes::new(slot, offset))
}
fn load<'s>(self) -> Self::Wraps<'s> {
StorageGuard::new(self)
}
fn load_mut<'s>(self) -> Self::WrapsMut<'s> {
StorageGuardMut::new(self)
}
}
impl StorageString {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn push(&mut self, c: char) {
for byte in c.to_string().bytes() {
self.0.push(byte)
}
}
pub fn get_string(&mut self) -> String {
let bytes = self.0.get_bytes();
String::from_utf8_lossy(&bytes).into()
}
pub fn set_str(&mut self, text: impl AsRef<str>) {
self.erase();
for c in text.as_ref().chars() {
self.push(c);
}
}
}
impl Erase for StorageString {
fn erase(&mut self) {
self.0.erase()
}
}
impl Extend<char> for StorageString {
fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
for c in iter {
self.push(c);
}
}
}