1use alloy_primitives::{B256, U256};
2use arb_storage_errors::StorageError;
3
4use crate::{
5 backed_types::StorageBackedUint64,
6 backend::{StorageBackend, SystemStateBackend},
7 slot::storage_key_map,
8 state_ops::ARBOS_STATE_ADDRESS,
9 storage::Storage,
10};
11
12#[derive(Clone, Copy, Debug)]
17pub struct Queue {
18 pub base_key: B256,
19 next_put: StorageBackedUint64,
20 next_get: StorageBackedUint64,
21}
22
23fn compute_slot(base_key: B256, offset: u64) -> U256 {
24 if base_key == B256::ZERO {
25 storage_key_map(&[], offset)
26 } else {
27 storage_key_map(base_key.as_slice(), offset)
28 }
29}
30
31pub fn initialize_queue<D: revm::Database>(storage: &Storage<'_, D>) -> Result<(), StorageError> {
32 storage.set_uint64_by_uint64(0, 2)?;
33 storage.set_uint64_by_uint64(1, 2)?;
34 Ok(())
35}
36
37pub fn open_queue<D>(storage: Storage<'_, D>) -> Queue {
38 open_queue_at(storage.base_key())
39}
40
41pub(crate) fn open_queue_at(base_key: B256) -> Queue {
42 Queue {
43 base_key,
44 next_put: StorageBackedUint64::new(base_key, 0),
45 next_get: StorageBackedUint64::new(base_key, 1),
46 }
47}
48
49impl Queue {
50 fn load_slot<B: SystemStateBackend>(
51 &self,
52 backend: &mut B,
53 offset: u64,
54 ) -> Result<B256, StorageError> {
55 let slot = compute_slot(self.base_key, offset);
56 let value = backend
57 .sload_system(ARBOS_STATE_ADDRESS, slot)
58 .map_err(Into::into)?;
59 Ok(B256::from(value.to_be_bytes::<32>()))
60 }
61
62 fn store_slot<B: StorageBackend>(
63 &self,
64 backend: &mut B,
65 offset: u64,
66 value: B256,
67 ) -> Result<(), StorageError> {
68 let slot = compute_slot(self.base_key, offset);
69 backend
70 .sstore(ARBOS_STATE_ADDRESS, slot, U256::from_be_bytes(value.0))
71 .map_err(Into::into)
72 }
73
74 pub fn is_empty<B: SystemStateBackend>(&self, backend: &mut B) -> Result<bool, StorageError> {
75 let put = self.next_put.get(backend)?;
76 let get = self.next_get.get(backend)?;
77 Ok(put == get)
78 }
79
80 pub fn size<B: SystemStateBackend>(&self, backend: &mut B) -> Result<u64, StorageError> {
81 let put = self.next_put.get(backend)?;
82 let get = self.next_get.get(backend)?;
83 Ok(put.saturating_sub(get))
84 }
85
86 pub fn peek<B: SystemStateBackend>(
87 &self,
88 backend: &mut B,
89 ) -> Result<Option<B256>, StorageError> {
90 if self.is_empty(backend)? {
91 return Ok(None);
92 }
93 let get = self.next_get.get(backend)?;
94 let val = self.load_slot(backend, get)?;
95 Ok(Some(val))
96 }
97
98 pub fn get<B: StorageBackend>(&self, backend: &mut B) -> Result<Option<B256>, StorageError> {
99 if self.is_empty(backend)? {
100 return Ok(None);
101 }
102 let get = self.next_get.get(backend)?;
103 let val = self.load_slot(backend, get)?;
104 self.store_slot(backend, get, B256::ZERO)?;
105 self.next_get.set(backend, get + 1)?;
106 Ok(Some(val))
107 }
108
109 pub fn put<B: StorageBackend>(&self, backend: &mut B, value: B256) -> Result<(), StorageError> {
110 let put = self.next_put.get(backend)?;
111 self.store_slot(backend, put, value)?;
112 self.next_put.set(backend, put + 1)?;
113 Ok(())
114 }
115
116 pub fn shift<B: StorageBackend>(&self, backend: &mut B) -> Result<Option<B256>, StorageError> {
118 if self.is_empty(backend)? {
119 return Ok(None);
120 }
121 let put = self.next_put.get(backend)?;
122 let idx = put - 1;
123 let val = self.load_slot(backend, idx)?;
124 self.store_slot(backend, idx, B256::ZERO)?;
125 self.next_put.set(backend, idx)?;
126 Ok(Some(val))
127 }
128
129 pub fn for_each<F, E, B>(&self, backend: &mut B, mut f: F) -> Result<(), E>
130 where
131 F: FnMut(B256) -> Result<(), E>,
132 E: From<StorageError>,
133 B: SystemStateBackend,
134 {
135 let get = self.next_get.get(backend)?;
136 let put = self.next_put.get(backend)?;
137 for i in get..put {
138 let val = self.load_slot(backend, i)?;
139 f(val)?;
140 }
141 Ok(())
142 }
143}