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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/// The types of stores that can be created.
#[derive(Debug, Clone, PartialEq)]
pub enum Store {
    /// Tree
    Tree,
    /// Data (block store)
    Data,
    /// Bitfield
    Bitfield,
    /// Oplog
    Oplog,
}

impl std::fmt::Display for Store {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Store::Tree => write!(f, "tree"),
            Store::Data => write!(f, "data"),
            Store::Bitfield => write!(f, "bitfield"),
            Store::Oplog => write!(f, "oplog"),
        }
    }
}

/// Information type about a store.
#[derive(Debug, PartialEq)]
pub(crate) enum StoreInfoType {
    /// Read/write content of the store
    Content,
    /// Size in bytes of the store. When flushed, truncates to the given index. `data` is `None`.
    Size,
}

/// Piece of information about a store. Useful for indicating changes that should be made to random
/// access storages or information read from them.
#[derive(Debug)]
pub(crate) struct StoreInfo {
    pub(crate) store: Store,
    pub(crate) info_type: StoreInfoType,
    pub(crate) index: u64,
    pub(crate) length: Option<u64>,
    pub(crate) data: Option<Box<[u8]>>,
    /// When reading, indicates missing value (can be true only if allow_miss is given as instruction).
    /// When writing indicates that the value should be dropped.
    pub(crate) miss: bool,
}

impl StoreInfo {
    pub(crate) fn new_content(store: Store, index: u64, data: &[u8]) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index,
            length: Some(data.len() as u64),
            data: Some(data.into()),
            miss: false,
        }
    }

    pub(crate) fn new_content_miss(store: Store, index: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index,
            length: None,
            data: None,
            miss: true,
        }
    }

    pub(crate) fn new_delete(store: Store, index: u64, length: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index,
            length: Some(length),
            data: None,
            miss: true,
        }
    }

    pub(crate) fn new_truncate(store: Store, index: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Size,
            index,
            length: None,
            data: None,
            miss: true,
        }
    }

    pub(crate) fn new_size(store: Store, index: u64, length: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Size,
            index,
            length: Some(length),
            data: None,
            miss: false,
        }
    }
}

/// Represents an instruction to obtain information about a store.
#[derive(Debug)]
pub(crate) struct StoreInfoInstruction {
    pub(crate) store: Store,
    pub(crate) info_type: StoreInfoType,
    pub(crate) index: u64,
    pub(crate) length: Option<u64>,
    pub(crate) allow_miss: bool,
}

impl StoreInfoInstruction {
    pub(crate) fn new_content(store: Store, index: u64, length: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index,
            length: Some(length),
            allow_miss: false,
        }
    }

    pub(crate) fn new_content_allow_miss(store: Store, index: u64, length: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index,
            length: Some(length),
            allow_miss: true,
        }
    }

    pub(crate) fn new_all_content(store: Store) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Content,
            index: 0,
            length: None,
            allow_miss: false,
        }
    }

    pub(crate) fn new_size(store: Store, index: u64) -> Self {
        Self {
            store,
            info_type: StoreInfoType::Size,
            index,
            length: None,
            allow_miss: false,
        }
    }
}