1use std::collections::HashMap;
18
19use wasefire_error::Error;
20
21use crate::format::Format;
22use crate::{StoreRatio, StoreUpdate, usize_to_nat};
23
24#[derive(Clone, Debug)]
29pub struct StoreModel {
30 content: HashMap<usize, Box<[u8]>>,
32
33 format: Format,
35}
36
37#[derive(Clone, Debug)]
39pub enum StoreOperation {
40 Transaction {
42 updates: Vec<StoreUpdate<Vec<u8>>>,
44 },
45
46 Clear {
48 min_key: usize,
50 },
51
52 Prepare {
54 length: usize,
56 },
57}
58
59impl StoreModel {
60 pub fn new(format: Format) -> StoreModel {
62 let content = HashMap::new();
63 StoreModel { content, format }
64 }
65
66 pub fn content(&self) -> &HashMap<usize, Box<[u8]>> {
68 &self.content
69 }
70
71 pub fn format(&self) -> &Format {
73 &self.format
74 }
75
76 pub fn apply(&mut self, operation: StoreOperation) -> Result<(), Error> {
78 match operation {
79 StoreOperation::Transaction { updates } => self.transaction(updates),
80 StoreOperation::Clear { min_key } => self.clear(min_key),
81 StoreOperation::Prepare { length } => self.prepare(length),
82 }
83 }
84
85 pub fn capacity(&self) -> StoreRatio {
87 let total = self.format.total_capacity();
88 let used =
89 usize_to_nat(self.content.values().map(|x| self.format.entry_size(x) as usize).sum());
90 StoreRatio { used, total }
91 }
92
93 fn transaction(&mut self, updates: Vec<StoreUpdate<Vec<u8>>>) -> Result<(), Error> {
95 if self.format.transaction_valid(&updates).is_none() {
97 return Err(crate::INVALID_ARGUMENT);
98 }
99 let capacity = self.format.transaction_capacity(&updates) as usize;
101 if self.capacity().remaining() < capacity {
102 return Err(crate::NO_CAPACITY);
103 }
104 for update in updates {
106 match update {
107 StoreUpdate::Insert { key, value } => {
108 self.content.insert(key, value.into_boxed_slice());
109 }
110 StoreUpdate::Remove { key } => {
111 self.content.remove(&key);
112 }
113 }
114 }
115 Ok(())
116 }
117
118 fn clear(&mut self, min_key: usize) -> Result<(), Error> {
120 if min_key > self.format.max_key() as usize {
121 return Err(crate::INVALID_ARGUMENT);
122 }
123 self.content.retain(|&k, _| k < min_key);
124 Ok(())
125 }
126
127 fn prepare(&self, length: usize) -> Result<(), Error> {
129 if self.capacity().remaining() < length {
130 return Err(crate::NO_CAPACITY);
131 }
132 Ok(())
133 }
134}