1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::{ByteArray32, StorageOutcome};
use borsh::{BorshDeserialize, BorshSerialize};

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, BorshSerialize, BorshDeserialize)]
pub struct StackMemDB<const S: usize> {
    storage: [ByteArray32; S],
}
impl<const S: usize> StackMemDB<S> {
    pub fn new() -> Self {
        StackMemDB {
            storage: [[0; 32]; S],
        }
    }

    pub fn storage_len(&self) -> usize {
        self.storage.len()
    }

    pub fn insert(&mut self, value: ByteArray32) -> StorageOutcome {
        if self.storage[0] != [0_u8; 32] {
            return StorageOutcome::CapacityExceeded;
        }

        match self.find(value) {
            None => {
                self.storage[0] = value;

                self.storage.sort_unstable();

                StorageOutcome::Inserted(value)
            }
            Some(value) => StorageOutcome::ValueExists(value),
        }
    }

    /// Returns the updated value if any
    /// and if the new value already exists, it will fail updating
    pub fn update(&mut self, old_value: ByteArray32, new_value: ByteArray32) -> StorageOutcome {
        match self.find(new_value) {
            None => (),
            Some(value) => return StorageOutcome::ValueExists(value),
        }

        match self.find_and_index(old_value) {
            (Some(index_found), _) => {
                self.storage[index_found] = new_value;

                StorageOutcome::Updated(old_value)
            }
            (None, _) => StorageOutcome::NonExistentValue(old_value),
        }
    }

    pub fn remove(&mut self, value: ByteArray32) -> StorageOutcome {
        match self.find_and_index(value) {
            (Some(index_found), _) => {
                self.storage[index_found] = [0_u8; 32];
                self.storage.sort_unstable();

                StorageOutcome::Zeroed(value)
            }
            (None, _) => StorageOutcome::NonExistentValue(value),
        }
    }

    pub fn find(&self, value: ByteArray32) -> Option<ByteArray32> {
        match self.storage.binary_search(&value) {
            Err(_) => None,
            Ok(_) => Some(value),
        }
    }

    ///FIXME Sometimes returns None
    /*


    let old_eve = match stack_memdb.find_and_index(eve) {
        (Some(index), _) => Some(index),
        (None, _) => None,
    };

    stack_memdb.update(eve, smith);

    let updated_eve = match stack_memdb.find_and_index(smith) {
        (Some(index), _) => Some(index),
        (None, _) => None,
    };

    assert_eq!(old_eve, updated_eve);
    */
    pub fn find_and_index(&self, value: ByteArray32) -> (Option<usize>, Option<ByteArray32>) {
        match self.storage.binary_search(&value) {
            Err(_) => (None, None),
            Ok(index_found) => (Some(index_found), Some(value)),
        }
    }
}

#[cfg(feature = "heap_available")]
use core::fmt;
#[cfg(feature = "heap_available")]
impl<const S: usize> fmt::Debug for StackMemDB<S> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let storage = self
            .storage
            .iter()
            .map(|value| hex::encode(value))
            .collect::<Vec<String>>();

        f.debug_struct("StackMemDb")
            .field("storage", &storage)
            .finish()
    }
}