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
use crate::database::database_description::DatabaseDescription;
use fuel_core_storage::{
    iter::{
        BoxedIter,
        IntoBoxedIter,
        IterDirection,
        IterableStore,
    },
    kv_store::{
        KVItem,
        KeyValueInspect,
        StorageColumn,
        Value,
        WriteOperation,
    },
    transactional::Changes,
    Result as StorageResult,
};
use std::{
    fmt::Debug,
    sync::Arc,
};

pub mod in_memory;
#[cfg(feature = "rocksdb")]
pub mod rocks_db;

#[allow(type_alias_bounds)]
pub type DataSource<Description>
where
    Description: DatabaseDescription,
= Arc<dyn TransactableStorage<Description::Height, Column = Description::Column>>;

pub trait TransactableStorage<Height>: IterableStore + Debug + Send + Sync {
    /// Commits the changes into the storage.
    fn commit_changes(
        &self,
        height: Option<Height>,
        changes: Changes,
    ) -> StorageResult<()>;
}

// It is used only to allow conversion of the `StorageTransaction` into the `DataSource`.
#[cfg(feature = "test-helpers")]
impl<Height, S> TransactableStorage<Height>
    for fuel_core_storage::transactional::StorageTransaction<S>
where
    S: IterableStore + Debug + Send + Sync,
{
    fn commit_changes(&self, _: Option<Height>, _: Changes) -> StorageResult<()> {
        unimplemented!()
    }
}

/// A type that allows to iterate over the `Changes`.
pub struct ChangesIterator<'a, Description> {
    changes: &'a Changes,
    _marker: core::marker::PhantomData<Description>,
}

impl<'a, Description> ChangesIterator<'a, Description> {
    /// Creates a new instance of the `ChangesIterator`.
    pub fn new(changes: &'a Changes) -> Self {
        Self {
            changes,
            _marker: Default::default(),
        }
    }
}

impl<'a, Description> KeyValueInspect for ChangesIterator<'a, Description>
where
    Description: DatabaseDescription,
{
    type Column = Description::Column;

    fn get(&self, key: &[u8], column: Self::Column) -> StorageResult<Option<Value>> {
        Ok(self
            .changes
            .get(&column.id())
            .and_then(|tree| tree.get(&key.to_vec()))
            .and_then(|operation| match operation {
                WriteOperation::Insert(value) => Some(value.clone()),
                WriteOperation::Remove => None,
            }))
    }
}

impl<'a, Description> IterableStore for ChangesIterator<'a, Description>
where
    Description: DatabaseDescription,
{
    fn iter_store(
        &self,
        column: Self::Column,
        prefix: Option<&[u8]>,
        start: Option<&[u8]>,
        direction: IterDirection,
    ) -> BoxedIter<KVItem> {
        if let Some(tree) = self.changes.get(&column.id()) {
            fuel_core_storage::iter::iterator(tree, prefix, start, direction)
                .filter_map(|(key, value)| match value {
                    WriteOperation::Insert(value) => Some((key.clone(), value.clone())),
                    WriteOperation::Remove => None,
                })
                .map(Ok)
                .into_boxed()
        } else {
            core::iter::empty().into_boxed()
        }
    }
}