ic_storage/adapter.rs
1//! Supported upstream collections with governed memory and an explicit API.
2//!
3//! Constructors preserve upstream initialization, panic and persisted-format
4//! contracts. These wrappers expose neither raw memory nor unrestricted
5//! upstream collections.
6//! Use distinct admitted allocations for owning collections. Region views retain
7//! a shared lease for disjoint application frames and reload roots per operation.
8//! Drop collections and all shared lease owners before reopening.
9//! IC Memory enforces one live lease per allocation within each runtime;
10//! hosts retain exclusive custody of the backing across runtimes.
11use crate::substrate::{self, DefaultMemoryImpl};
12use ic_memory::RuntimeMemory;
13use std::{borrow::Cow, ops::RangeBounds};
14/// Exact substrate interfaces for backing bounds and record codecs.
15/// Implementing `Memory` grants no allocation authority; constructors require
16/// committed `RuntimeMemory` leases.
17pub use substrate::{Memory, Storable, storable, storable::Bound};
18
19#[cfg(all(test, not(target_arch = "wasm32")))]
20mod tests;
21
22mod region;
23pub use region::{BTreeMapRegion, RegionGrowError};
24
25/// Governed upstream `BTreeMap`; initialization and failures follow upstream contracts.
26pub struct StableBTreeMap<K: Storable + Ord + Clone, V: Storable, M: Memory = DefaultMemoryImpl> {
27 inner: substrate::BTreeMap<K, V, RuntimeMemory<M>>,
28}
29impl<K: Storable + Ord + Clone, V: Storable, M: Memory> StableBTreeMap<K, V, M> {
30 /// Create a new collection, replacing any prior collection in the selected memory.
31 /// This is destructive even when a valid collection already exists.
32 ///
33 /// # Panics
34 /// Panics on insufficient memory or codec/backing failure.
35 pub fn new(memory: RuntimeMemory<M>) -> Self {
36 Self {
37 inner: substrate::BTreeMap::new(memory),
38 }
39 }
40 /// Open a recognized retained collection; initialize a new one when memory
41 /// is empty or has foreign magic. Foreign contents may be overwritten.
42 /// This is not a corruption-recovery or schema-admission operation.
43 ///
44 /// # Panics
45 /// Panics for unsupported recognized layouts, invalid retained contents,
46 /// insufficient memory or codec/backing failure.
47 pub fn init(memory: RuntimeMemory<M>) -> Self {
48 Self {
49 inner: substrate::BTreeMap::init(memory),
50 }
51 }
52 /// Load an existing tree without initializing a replacement.
53 ///
54 /// # Panics
55 /// Panics for missing/foreign headers, unsupported layouts or backing failure.
56 /// Record decoding can also panic when records are subsequently accessed.
57 pub fn load(memory: RuntimeMemory<M>) -> Self {
58 Self {
59 inner: substrate::BTreeMap::load(memory),
60 }
61 }
62 /// Clear entries while retaining this allocation's exclusive lease.
63 pub fn clear(&mut self) {
64 self.inner.clear_new();
65 }
66 /// Reserve a minimum virtual extent without exposing or duplicating the lease.
67 ///
68 /// Returns the map on both success and ordinary growth refusal. Entries are
69 /// preserved; reloading the upstream header refreshes its cached allocator.
70 /// Backing traps retain the upstream panic contract.
71 ///
72 /// `minimum` is an absolute virtual extent in 65,536-byte Wasm pages, not an
73 /// entry count or additional pages. Existing extents never shrink. A request
74 /// already covered performs no growth or writes. This reserves backing only:
75 /// it does not promise that any particular number or encoding of entries fits.
76 /// Callers own their byte/page budget and must qualify it for their codecs;
77 /// upstream node-layout constants are not a supported capacity contract.
78 pub fn reserve_pages(self, minimum: u64) -> (Self, Result<(), ic_memory::RuntimeGrowError>) {
79 let memory = self.inner.into_memory();
80 let additional = minimum.saturating_sub(memory.size());
81 let result = memory.grow(additional).map(|_| ());
82 (Self::load(memory), result)
83 }
84 /// Observe the virtual extent in 65,536-byte pages while retaining the lease.
85 ///
86 /// Consumes and returns the map because upstream exposes memory only through
87 /// ownership transfer. Reloading reads the header without writing or growing.
88 /// This is allocated extent, not free space or guaranteed entry capacity.
89 #[must_use]
90 pub fn allocated_pages(self) -> (Self, u64) {
91 let memory = self.inner.into_memory();
92 let pages = memory.size();
93 (Self::load(memory), pages)
94 }
95 /// Delegates to upstream `BTreeMap::insert` with the governed allocation.
96 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
97 self.inner.insert(key, value)
98 }
99 /// Delegates to upstream `BTreeMap::get` with the governed allocation.
100 pub fn get(&self, key: &K) -> Option<V> {
101 self.inner.get(key)
102 }
103 /// Delegates to upstream `BTreeMap::contains_key` with the governed allocation.
104 pub fn contains_key(&self, key: &K) -> bool {
105 self.inner.contains_key(key)
106 }
107 /// Delegates to upstream `BTreeMap::is_empty` with the governed allocation.
108 pub fn is_empty(&self) -> bool {
109 self.inner.is_empty()
110 }
111 /// Delegates to upstream `BTreeMap::len` with the governed allocation.
112 pub fn len(&self) -> u64 {
113 self.inner.len()
114 }
115 /// Delegates to upstream `BTreeMap::remove` with the governed allocation.
116 pub fn remove(&mut self, key: &K) -> Option<V> {
117 self.inner.remove(key)
118 }
119 /// Delegates to upstream `BTreeMap::first_key_value` with the governed allocation.
120 pub fn first_key_value(&self) -> Option<(K, V)> {
121 self.inner.first_key_value()
122 }
123 /// Delegates to upstream `BTreeMap::last_key_value` with the governed allocation.
124 pub fn last_key_value(&self) -> Option<(K, V)> {
125 self.inner.last_key_value()
126 }
127 /// Delegates to upstream `BTreeMap::pop_first` with the governed allocation.
128 pub fn pop_first(&mut self) -> Option<(K, V)> {
129 self.inner.pop_first()
130 }
131 /// Delegates to upstream `BTreeMap::pop_last` with the governed allocation.
132 pub fn pop_last(&mut self) -> Option<(K, V)> {
133 self.inner.pop_last()
134 }
135 /// Delegates to upstream `BTreeMap::iter` with the governed allocation.
136 pub fn iter(&self) -> MapIter<'_, K, V, M> {
137 self.inner.iter()
138 }
139 /// Delegates to upstream `BTreeMap::range` with the governed allocation.
140 pub fn range(&self, key_range: impl RangeBounds<K>) -> MapIter<'_, K, V, M> {
141 self.inner.range(key_range)
142 }
143 /// Delegates to upstream `BTreeMap::keys` with the governed allocation.
144 pub fn keys(&self) -> impl DoubleEndedIterator<Item = K> + '_ {
145 self.inner.keys()
146 }
147 /// Delegates to upstream `BTreeMap::values` with the governed allocation.
148 pub fn values(&self) -> impl DoubleEndedIterator<Item = V> + '_ {
149 self.inner.values()
150 }
151}
152
153/// Governed upstream `BTreeSet`; initialization and failures follow upstream contracts.
154pub struct StableBTreeSet<K: Storable + Ord + Clone, M: Memory = DefaultMemoryImpl> {
155 inner: substrate::BTreeSet<K, RuntimeMemory<M>>,
156}
157impl<K: Storable + Ord + Clone, M: Memory> StableBTreeSet<K, M> {
158 /// Create a new collection, replacing any prior collection in the selected memory.
159 /// This is destructive even when a valid collection already exists.
160 ///
161 /// # Panics
162 /// Panics on insufficient memory or codec/backing failure.
163 pub fn new(memory: RuntimeMemory<M>) -> Self {
164 Self {
165 inner: substrate::BTreeSet::new(memory),
166 }
167 }
168 /// Open a recognized retained collection; initialize a new one when memory
169 /// is empty or has foreign magic. Foreign contents may be overwritten.
170 /// This is not a corruption-recovery or schema-admission operation.
171 ///
172 /// # Panics
173 /// Panics for unsupported recognized layouts, invalid retained contents,
174 /// insufficient memory or codec/backing failure.
175 pub fn init(memory: RuntimeMemory<M>) -> Self {
176 Self {
177 inner: substrate::BTreeSet::init(memory),
178 }
179 }
180 /// Load an existing tree without initializing a replacement.
181 ///
182 /// # Panics
183 /// Panics for missing/foreign headers, unsupported layouts or backing failure.
184 /// Record decoding can also panic when records are subsequently accessed.
185 pub fn load(memory: RuntimeMemory<M>) -> Self {
186 Self {
187 inner: substrate::BTreeSet::load(memory),
188 }
189 }
190 /// Delegates to upstream `BTreeSet::insert` with the governed allocation.
191 pub fn insert(&mut self, key: K) -> bool {
192 self.inner.insert(key)
193 }
194 /// Delegates to upstream `BTreeSet::contains` with the governed allocation.
195 pub fn contains(&self, key: &K) -> bool {
196 self.inner.contains(key)
197 }
198 /// Delegates to upstream `BTreeSet::is_empty` with the governed allocation.
199 pub fn is_empty(&self) -> bool {
200 self.inner.is_empty()
201 }
202 /// Delegates to upstream `BTreeSet::len` with the governed allocation.
203 pub fn len(&self) -> u64 {
204 self.inner.len()
205 }
206 /// Delegates to upstream `BTreeSet::remove` with the governed allocation.
207 pub fn remove(&mut self, key: &K) -> bool {
208 self.inner.remove(key)
209 }
210 /// Delegates to upstream `BTreeSet::first` with the governed allocation.
211 pub fn first(&self) -> Option<K> {
212 self.inner.first()
213 }
214 /// Delegates to upstream `BTreeSet::last` with the governed allocation.
215 pub fn last(&self) -> Option<K> {
216 self.inner.last()
217 }
218 /// Delegates to upstream `BTreeSet::pop_first` with the governed allocation.
219 pub fn pop_first(&mut self) -> Option<K> {
220 self.inner.pop_first()
221 }
222 /// Delegates to upstream `BTreeSet::pop_last` with the governed allocation.
223 pub fn pop_last(&mut self) -> Option<K> {
224 self.inner.pop_last()
225 }
226 /// Delegates to upstream `BTreeSet::iter` with the governed allocation.
227 pub fn iter(&self) -> SetIter<'_, K, M> {
228 self.inner.iter()
229 }
230 /// Delegates to upstream `BTreeSet::range` with the governed allocation.
231 pub fn range(&self, key_range: impl RangeBounds<K>) -> SetIter<'_, K, M> {
232 self.inner.range(key_range)
233 }
234 /// Delegates to upstream `BTreeSet::clear` with the governed allocation.
235 pub fn clear(&mut self) {
236 self.inner.clear();
237 }
238}
239
240///
241/// `StableCell`
242///
243/// Governed upstream `Cell` with explicit initialization and read-only loading.
244///
245/// Values and stored bytes retain the upstream codec and layout contracts.
246///
247pub struct StableCell<T: Storable, M: Memory = DefaultMemoryImpl> {
248 inner: substrate::Cell<CellValue<T>, RuntimeMemory<M>>,
249}
250
251// Upstream has no load constructor. An absent value is an internal loading
252// marker, never a default T or a persisted record. Serialization refuses it
253// before upstream can grow/write on its initialization fallback. Successful
254// construction always holds Some(T), decoded exactly once by upstream.
255struct CellValue<T>(Option<T>);
256
257impl<T: Storable> Storable for CellValue<T> {
258 const BOUND: Bound = T::BOUND;
259
260 fn to_bytes(&self) -> Cow<'_, [u8]> {
261 self.0
262 .as_ref()
263 .expect("cannot initialize a loading cell")
264 .to_bytes()
265 }
266
267 fn into_bytes(self) -> Vec<u8> {
268 self.0
269 .expect("cannot initialize a loading cell")
270 .into_bytes()
271 }
272
273 fn from_bytes(bytes: Cow<'_, [u8]>) -> Self {
274 Self(Some(T::from_bytes(bytes)))
275 }
276}
277
278impl<T: Storable, M: Memory> StableCell<T, M> {
279 /// Create a new collection, replacing any prior collection in the selected memory.
280 /// This is destructive even when a valid collection already exists.
281 ///
282 /// # Panics
283 /// Panics on insufficient memory or codec/backing failure.
284 pub fn new(memory: RuntimeMemory<M>, value: T) -> Self {
285 Self {
286 inner: substrate::Cell::new(memory, CellValue(Some(value))),
287 }
288 }
289 /// Open a recognized retained collection; initialize a new one when memory
290 /// is empty or has foreign magic. Foreign contents may be overwritten.
291 /// This is not a corruption-recovery or schema-admission operation.
292 ///
293 /// # Panics
294 /// Panics for unsupported recognized layouts, invalid retained contents,
295 /// insufficient memory or codec/backing failure.
296 pub fn init(memory: RuntimeMemory<M>, default_value: T) -> Self {
297 Self {
298 inner: substrate::Cell::init(memory, CellValue(Some(default_value))),
299 }
300 }
301 /// Load an existing cell without initializing, writing or growing memory.
302 ///
303 /// Requires no default value or `Default`/`Clone` bound. The retained value
304 /// is decoded by upstream using `T::from_bytes`. A successful load retains
305 /// the allocation's exclusive lease until this cell is dropped.
306 ///
307 /// # Errors
308 /// Returns [`ic_memory::StableCellPayloadError`] for empty/foreign memory,
309 /// unsupported layout versions or a payload extending beyond memory. The
310 /// consumed lease is released on failure; no bytes are changed.
311 ///
312 /// # Panics
313 /// Codec and backing failures propagate as upstream panics. Loading does
314 /// not write or grow even on these failures. Ordinary unwinding releases
315 /// the consumed lease; Wasm traps retain the host's rollback semantics.
316 /// This validates the envelope, not the application's schema or recovery policy.
317 pub fn load(memory: RuntimeMemory<M>) -> Result<Self, ic_memory::StableCellPayloadError> {
318 ic_memory::stable_cell_payload_length(&memory, usize::MAX)?;
319 Ok(Self {
320 inner: substrate::Cell::init(memory, CellValue(None)),
321 })
322 }
323 /// Delegates to upstream `Cell::get` with the governed allocation.
324 #[expect(
325 clippy::missing_panics_doc,
326 reason = "constructors always establish a cached value"
327 )]
328 pub fn get(&self) -> &T {
329 self.inner.get().0.as_ref().expect("loaded cell value")
330 }
331 /// Delegates to upstream `Cell::set` with the governed allocation.
332 ///
333 /// # Panics
334 /// Panics on insufficient memory or codec/backing failure, as upstream.
335 pub fn set(&mut self, value: T) -> T {
336 self.inner
337 .set(CellValue(Some(value)))
338 .0
339 .expect("loaded cell value")
340 }
341}
342
343/// Governed upstream `Vec`; initialization and failures follow upstream contracts.
344pub struct StableVec<T: Storable, M: Memory = DefaultMemoryImpl> {
345 inner: substrate::Vec<T, RuntimeMemory<M>>,
346}
347impl<T: Storable, M: Memory> StableVec<T, M> {
348 /// Create a new collection, replacing any prior collection in the selected memory.
349 /// This is destructive even when a valid collection already exists.
350 ///
351 /// # Panics
352 /// Panics on insufficient memory or codec/backing failure.
353 pub fn new(memory: RuntimeMemory<M>) -> Self {
354 Self {
355 inner: substrate::Vec::new(memory),
356 }
357 }
358 /// Open a valid retained collection, or create one in zero-page memory.
359 ///
360 /// # Panics
361 /// Panics for foreign magic, unsupported layout, incompatible element bounds,
362 /// insufficient memory or codec/backing failure. Foreign memory is not reset.
363 pub fn init(memory: RuntimeMemory<M>) -> Self {
364 Self {
365 inner: substrate::Vec::init(memory),
366 }
367 }
368 /// Delegates to upstream `Vec::get` with the governed allocation.
369 pub fn get(&self, index: u64) -> Option<T> {
370 self.inner.get(index)
371 }
372 /// Delegates to upstream `Vec::set` with the governed allocation.
373 pub fn set(&self, index: u64, item: &T) {
374 self.inner.set(index, item);
375 }
376 /// Delegates to upstream `Vec::push` with the governed allocation.
377 pub fn push(&self, item: &T) {
378 self.inner.push(item);
379 }
380 /// Delegates to upstream `Vec::pop` with the governed allocation.
381 pub fn pop(&self) -> Option<T> {
382 self.inner.pop()
383 }
384 /// Reset to an empty vector while retaining this allocation's exclusive lease.
385 /// Existing payload bytes follow upstream `Vec::new` semantics.
386 #[must_use]
387 pub fn reset(self) -> Self {
388 Self::new(self.inner.into_memory())
389 }
390 /// Delegates to upstream `Vec::len` with the governed allocation.
391 pub fn len(&self) -> u64 {
392 self.inner.len()
393 }
394 /// Delegates to upstream `Vec::is_empty` with the governed allocation.
395 pub fn is_empty(&self) -> bool {
396 self.inner.is_empty()
397 }
398 /// Delegates to upstream `Vec::iter` with the governed allocation.
399 pub fn iter(&self) -> impl DoubleEndedIterator<Item = T> + '_ {
400 self.inner.iter()
401 }
402}
403
404/// Governed upstream `MinHeap`; initialization and failures follow upstream contracts.
405pub struct StableMinHeap<T: Storable + Ord, M: Memory = DefaultMemoryImpl> {
406 inner: substrate::MinHeap<T, RuntimeMemory<M>>,
407}
408impl<T: Storable + Ord, M: Memory> StableMinHeap<T, M> {
409 /// Create a new collection, replacing any prior collection in the selected memory.
410 /// This is destructive even when a valid collection already exists.
411 ///
412 /// # Panics
413 /// Panics on insufficient memory or codec/backing failure.
414 pub fn new(memory: RuntimeMemory<M>) -> Self {
415 Self {
416 inner: substrate::MinHeap::new(memory),
417 }
418 }
419 /// Open a valid retained collection, or create one in zero-page memory.
420 ///
421 /// # Panics
422 /// Panics for foreign magic, unsupported layout, incompatible element bounds,
423 /// insufficient memory or codec/backing failure. Foreign memory is not reset.
424 pub fn init(memory: RuntimeMemory<M>) -> Self {
425 Self {
426 inner: substrate::MinHeap::init(memory),
427 }
428 }
429 /// Delegates to upstream `MinHeap::push` with the governed allocation.
430 pub fn push(&mut self, item: &T) {
431 self.inner.push(item);
432 }
433 /// Delegates to upstream `MinHeap::pop` with the governed allocation.
434 pub fn pop(&mut self) -> Option<T> {
435 self.inner.pop()
436 }
437 /// Delegates to upstream `MinHeap::peek` with the governed allocation.
438 pub fn peek(&self) -> Option<T> {
439 self.inner.peek()
440 }
441 /// Delegates to upstream `MinHeap::len` with the governed allocation.
442 pub fn len(&self) -> u64 {
443 self.inner.len()
444 }
445 /// Delegates to upstream `MinHeap::is_empty` with the governed allocation.
446 pub fn is_empty(&self) -> bool {
447 self.inner.is_empty()
448 }
449 /// Delegates to upstream `MinHeap::iter` with the governed allocation.
450 pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
451 self.inner.iter()
452 }
453}
454
455/// Governed upstream `Log`; initialization and failures follow upstream contracts.
456pub struct StableLog<T: Storable, M: Memory = DefaultMemoryImpl> {
457 inner: substrate::Log<T, RuntimeMemory<M>, RuntimeMemory<M>>,
458}
459impl<T: Storable, M: Memory> StableLog<T, M> {
460 /// Create a new collection, replacing any prior collection in the selected memory.
461 /// This is destructive even when a valid collection already exists.
462 ///
463 /// # Panics
464 /// Panics on insufficient memory or codec/backing failure.
465 pub fn new(index_memory: RuntimeMemory<M>, data_memory: RuntimeMemory<M>) -> Self {
466 Self {
467 inner: substrate::Log::new(index_memory, data_memory),
468 }
469 }
470 /// Open a retained log, or initialize both memories when data memory is
471 /// empty or has foreign magic. The latter overwrites previous contents.
472 ///
473 /// # Panics
474 /// With recognized data magic, panics for an invalid index or unsupported
475 /// layout. Growth and codec/backing failures also retain upstream panics.
476 pub fn init(index_memory: RuntimeMemory<M>, data_memory: RuntimeMemory<M>) -> Self {
477 Self {
478 inner: substrate::Log::init(index_memory, data_memory),
479 }
480 }
481 /// Delegates to upstream `Log::first` with the governed allocation.
482 pub fn first(&self) -> Option<T> {
483 self.inner.first()
484 }
485 /// Delegates to upstream `Log::last` with the governed allocation.
486 pub fn last(&self) -> Option<T> {
487 self.inner.last()
488 }
489 /// Delegates to upstream `Log::get` with the governed allocation.
490 pub fn get(&self, idx: u64) -> Option<T> {
491 self.inner.get(idx)
492 }
493 /// Delegates to upstream `Log::len` with the governed allocation.
494 pub fn len(&self) -> u64 {
495 self.inner.len()
496 }
497 /// Delegates to upstream `Log::is_empty` with the governed allocation.
498 pub fn is_empty(&self) -> bool {
499 self.inner.is_empty()
500 }
501 /// Delegates to upstream `Log::append` with the governed allocation.
502 /// # Errors
503 /// Returns the upstream write error if memory cannot grow.
504 pub fn append(&self, item: &T) -> Result<u64, LogWriteError> {
505 self.inner.append(item)
506 }
507 /// Delegates to upstream `Log::iter` with the governed allocation.
508 pub fn iter(&self) -> LogIter<'_, T, M> {
509 self.inner.iter()
510 }
511}
512
513/// Upstream map iterator with governed memory.
514pub type MapIter<'a, K, V, M = DefaultMemoryImpl> =
515 substrate::btreemap::Iter<'a, K, V, RuntimeMemory<M>>;
516/// Upstream set iterator with governed memory.
517pub type SetIter<'a, K, M = DefaultMemoryImpl> = substrate::btreeset::Iter<'a, K, RuntimeMemory<M>>;
518/// Upstream log iterator with governed index and data memories.
519pub type LogIter<'a, T, M = DefaultMemoryImpl> =
520 substrate::log::Iter<'a, T, RuntimeMemory<M>, RuntimeMemory<M>>;
521
522pub use substrate::log::WriteError as LogWriteError;
523
524impl<'a, K: Storable + Ord + Clone, V: Storable, M: Memory> IntoIterator
525 for &'a StableBTreeMap<K, V, M>
526{
527 type Item = <MapIter<'a, K, V, M> as Iterator>::Item;
528 type IntoIter = MapIter<'a, K, V, M>;
529 fn into_iter(self) -> Self::IntoIter {
530 self.iter()
531 }
532}
533
534impl<'a, K: Storable + Ord + Clone, M: Memory> IntoIterator for &'a StableBTreeSet<K, M> {
535 type Item = K;
536 type IntoIter = SetIter<'a, K, M>;
537 fn into_iter(self) -> Self::IntoIter {
538 self.iter()
539 }
540}
541
542impl<'a, T: Storable, M: Memory> IntoIterator for &'a StableLog<T, M> {
543 type Item = T;
544 type IntoIter = LogIter<'a, T, M>;
545 fn into_iter(self) -> Self::IntoIter {
546 self.iter()
547 }
548}
549/// A stable cell whose writes enforce the record's declared `Storable` bound.
550pub struct BoundedCell<T: Storable, M: Memory = DefaultMemoryImpl> {
551 cell: substrate::Cell<BoundedValue<T>, RuntimeMemory<M>>,
552}
553
554impl<T: Storable, M: Memory> BoundedCell<T, M> {
555 /// Open a current cell or initialize a fresh bounded record.
556 /// Empty memory or foreign magic initializes the supplied value, potentially
557 /// overwriting foreign contents. Recognized incompatible layouts are refused.
558 ///
559 /// # Panics
560 /// Panics for unbounded records or encodings that violate the declared bound.
561 /// Also retains [`StableCell::init`] layout, growth and codec/backing panics.
562 #[must_use]
563 pub fn init(memory: RuntimeMemory<M>, value: T) -> Self {
564 assert!(matches!(T::BOUND, Bound::Bounded { .. }));
565 Self {
566 cell: substrate::Cell::init(memory, BoundedValue(value)),
567 }
568 }
569
570 /// Read the cached current record without serializing or cloning it.
571 #[must_use]
572 pub fn get(&self) -> &T {
573 &self.cell.get().0
574 }
575
576 /// Validate and persist a complete replacement, returning the prior record.
577 ///
578 /// # Panics
579 /// Panics before writing if the encoding violates its declared bound.
580 pub fn set(&mut self, value: T) -> T {
581 self.cell.set(BoundedValue(value)).0
582 }
583}
584
585struct BoundedValue<T>(T);
586
587impl<T: Storable> Storable for BoundedValue<T> {
588 const BOUND: Bound = T::BOUND;
589
590 fn to_bytes(&self) -> Cow<'_, [u8]> {
591 self.0.to_bytes_checked()
592 }
593
594 fn into_bytes(self) -> Vec<u8> {
595 self.0.into_bytes_checked()
596 }
597
598 fn from_bytes(bytes: Cow<'_, [u8]>) -> Self {
599 let Bound::Bounded {
600 max_size,
601 is_fixed_size,
602 } = T::BOUND
603 else {
604 unreachable!("bounded cell record must declare a bound");
605 };
606 if is_fixed_size {
607 assert_eq!(bytes.len(), max_size as usize);
608 } else {
609 assert!(bytes.len() <= max_size as usize);
610 }
611 Self(T::from_bytes(bytes))
612 }
613}