ic_storage/adapter/
vector.rs1use super::{
3 Memory, Storable,
4 error::{CollectionError as Error, Result, ensure},
5 record,
6};
7use crate::{DefaultMemoryImpl, RuntimeMemory, hash};
8use serde::{Deserialize, Serialize};
9use std::{borrow::Cow, cell::Cell, marker::PhantomData};
10
11const MAGIC: [u8; 8] = *b"ICVECC01";
12const DATA: u64 = record::HEADER_BYTES;
13const SLOT_HEADER: usize = 12;
14
15#[derive(Clone, Serialize, Deserialize)]
16struct Root {
17 length: u64,
18 bound: (u32, bool),
19}
20
21pub struct StableVec<T: Storable, M: Memory = DefaultMemoryImpl> {
29 memory: RuntimeMemory<M>,
30 length: Cell<u64>,
31 poisoned: Cell<bool>,
32 record: PhantomData<T>,
33}
34
35impl<T: Storable, M: Memory> StableVec<T, M> {
36 pub fn create(memory: RuntimeMemory<M>) -> Result<Self> {
41 ensure(memory.size() == 0, Error::NotEmpty)?;
42 Self::reset(memory)
43 }
44 pub fn reset(memory: RuntimeMemory<M>) -> Result<Self> {
49 let bytes = Self::header(0)?;
50 record::reserve(&memory, DATA)?;
51 memory.write(0, &bytes);
52 Ok(Self {
53 memory,
54 length: Cell::new(0),
55 poisoned: Cell::new(false),
56 record: PhantomData,
57 })
58 }
59 pub fn load(memory: RuntimeMemory<M>) -> Result<Self> {
64 let root: Root = record::read(&memory, 0, DATA, MAGIC)?;
65 ensure(
66 root.bound == Self::bound()?,
67 Error::Corrupt("vector codec bound changed"),
68 )?;
69 ensure(
70 Self::end(root.length)?
71 <= memory
72 .size()
73 .checked_mul(crate::WASM_PAGE_SIZE_BYTES)
74 .ok_or(Error::Budget)?,
75 Error::Corrupt("vector length exceeds memory"),
76 )?;
77 Ok(Self {
78 memory,
79 length: Cell::new(root.length),
80 poisoned: Cell::new(false),
81 record: PhantomData,
82 })
83 }
84 fn bound() -> Result<(u32, bool)> {
85 record::bound::<T>().ok_or(Error::Corrupt("vector requires a finite value bound"))
86 }
87 fn end(length: u64) -> Result<u64> {
88 let stride = u64::from(Self::bound()?.0) + SLOT_HEADER as u64;
89 DATA.checked_add(length.checked_mul(stride).ok_or(Error::Budget)?)
90 .ok_or(Error::Budget)
91 }
92 fn header(length: u64) -> Result<Vec<u8>> {
93 let bytes = record::encode(
94 MAGIC,
95 &Root {
96 length,
97 bound: Self::bound()?,
98 },
99 )?;
100 ensure(bytes.len() as u64 <= DATA, Error::Budget)?;
101 Ok(bytes)
102 }
103 fn healthy(&self) -> Result<()> {
104 ensure(!self.poisoned.get(), Error::Poisoned)
105 }
106
107 pub fn get(&self, index: u64) -> Result<Option<T>> {
115 self.healthy()?;
116 if index >= self.length.get() {
117 return Ok(None);
118 }
119 let offset = Self::end(index)?;
120 let mut header = [0; SLOT_HEADER];
121 self.memory.read(offset, &mut header);
122 let length = u32::from_le_bytes(header[..4].try_into().unwrap());
123 ensure(
124 length <= Self::bound()?.0,
125 Error::Corrupt("vector slot length exceeds bound"),
126 )?;
127 let mut bytes = vec![0; length as usize];
128 self.memory.read(offset + SLOT_HEADER as u64, &mut bytes);
129 let digest = u64::from_le_bytes(header[4..].try_into().unwrap());
130 ensure(
131 checksum(index, &header[..4], &bytes) == digest,
132 Error::Checksum,
133 )?;
134 T::check_bounds(&bytes)?;
135 Ok(Some(T::from_bytes(Cow::Owned(bytes))?))
136 }
137 pub fn set(&self, index: u64, item: &T) -> Result<()> {
142 self.healthy()?;
143 ensure(index < self.length.get(), Error::Bounds)?;
144 let bytes = item.to_bytes_checked()?;
145 self.write_slot(index, &bytes)
146 }
147 fn write_slot(&self, index: u64, bytes: &[u8]) -> Result<()> {
148 let offset = Self::end(index)?;
149 let mut header = [0; SLOT_HEADER];
150 let length = u32::try_from(bytes.len()).map_err(|_| Error::Budget)?;
151 header[..4].copy_from_slice(&length.to_le_bytes());
152 let digest = checksum(index, &header[..4], bytes);
153 header[4..].copy_from_slice(&digest.to_le_bytes());
154 self.poisoned.set(true);
155 self.memory.write(offset + SLOT_HEADER as u64, bytes);
156 self.memory.write(offset, &header);
157 self.poisoned.set(false);
158 Ok(())
159 }
160 pub fn push(&self, item: &T) -> Result<()> {
165 self.healthy()?;
166 let bytes = item.to_bytes_checked()?;
167 let length = self.length.get().checked_add(1).ok_or(Error::Budget)?;
168 let header = Self::header(length)?;
169 record::reserve(&self.memory, Self::end(length)?)?;
170 self.write_slot(length - 1, &bytes)?;
171 self.poisoned.set(true);
172 self.memory.write(0, &header);
173 self.length.set(length);
174 self.poisoned.set(false);
175 Ok(())
176 }
177 pub fn pop(&self) -> Result<Option<T>> {
182 self.healthy()?;
183 let Some(length) = self.length.get().checked_sub(1) else {
184 return Ok(None);
185 };
186 let value = self.get(length)?;
187 let header = Self::header(length)?;
188 self.poisoned.set(true);
189 self.memory.write(0, &header);
190 self.length.set(length);
191 self.poisoned.set(false);
192 Ok(value)
193 }
194 pub fn len(&self) -> u64 {
199 self.healthy().expect("vector owner is poisoned");
200 self.length.get()
201 }
202 pub fn is_empty(&self) -> bool {
204 self.len() == 0
205 }
206 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<T>> + '_ {
208 (0..self.len()).map(|index| self.get(index)?.ok_or(Error::Bounds))
209 }
210}
211
212fn checksum(index: u64, length: &[u8], bytes: &[u8]) -> u64 {
213 let digest = hash::fnv64(hash::FNV_OFFSET, &index.to_le_bytes());
214 hash::fnv64(hash::fnv64(digest, length), bytes)
215}