Skip to content

Commit dffc8cf

Browse files
Robbepopascjones
andauthored
Implement storage (revision 2) module (#311)
* [core] apply rustfmt * [core] fix warnings related to Wasm compilation * [core] add SpreadLayout impl for DynamicAllocator * [core] remove unused method on Bits256RefMut * [core] apply rustfmt * [core] remove some unneded ToDo comments The ToDo comments have been moved to the associated PR description. * [core] transit to new traits for LazyIndexMap * [core] transit to new traits for storage::Vec * [core] transit to new traits for storage::Stash * [core] transit to new traits for storage::Bitvec * [core] transit to new traits for dynamic storage allocator * [core] transit to new traits for LazyHashMap * [core] transit to new traits for storage::HashMap * [core] apply rustfmt * [core] remove old storage traits for storage::Pack * [core] transit to new storage traits for LazyArray * [core] transit to new storage traits for storage::SmallVec * [core] transit to new storage traits for the rest of the lazy abstractions * [core] transit to new storage traits for storage::Box * [core] fix compile error in Drop impl for storage::Box * [core] remove old storage trait impls for Bits256 * [core] remove old storage trait impls for dynamic storage allocator * [core] apply rustfmt * [core] remove old traits module * [core] replace KeyPtr2 usage with KeyPtr * [core] rename traits2 module to traits * [core] apply rustfmt * [core] add Drop impl to storage::Vec * [core] don't clear storage if key is none for storage::Vec * [core] impl Drop for storage::Stash * [core] simplify trait bounds for LazyHashMap * [core] impl Drop for storage::HashMap * [core] add Drop impl for storage::SmallVec * [core] add are_trait_objects lint as deny * [core] fix minor formatting issue * [core] add storage2::Memory utility * [core] remove usage of storage::Pack from internals of storage::Bitvec * [core] remove usage of storage::Pack from internals of storage::Stash * [core] remove usage of storage::Pack from internals of storage::HashMap * [core] add better Debug impl for LazyIndexMap The improved impl shows the cached entries which were hidden in the old impl behind the UnsafeCell. * [core] apply rustfmt * [core] improve Debug impl for LazyHashMap It now displays its internal cached entries. * [core] improve Debug impl for lazy::Entry * [core] improve Debug impl for LazyCell * [core] improve Debug impl for LazyArray * [core] apply rustfmt * [core] add REQUIRES_DEEP_CLEAN_UP to SpreadLayout With this we have a way for types to perform an optimized storage clean-up without having to load them in case they do not require a deep clean-up of their state. * [core] implement REQUIRES_DEEP_CLEAN_UP for all built-in types * [core] add non-storage trait impls for storage::HashMap * [core] simplify traits bounds of SpreadLayout impl for storage::HashMap * [core] fix bug in Wasm compilation * [core] add initial unit tests for storage::HashMap * [core] allow loading without key from LazyHashMap * [core] merge storage::HashMap insert and insert_get and fix bugs with it * [core] add new unit test for storage::HashMap * [core] generally allow lazy loading without keys for lazy abstractions * [core] apply rustfmt * [core] remove outdated docs of storage::HashMap::insert * [core] add unit test for storage::HashMap::contains_key * [core] apply rustfmt to storage::HashMap unit tests * [core] add unit test for storage::HashMap::{get, get_mut} * [core] fix the doc comment of storage::HashMap::remove * [core] add unit test for storage::HashMap::take * [core] add unit test for storage::HashMap::insert * [core] remove storage::HashMap::remove The API cannot be implemented properly at this point. * [core] implement Iterator::count efficiently for storage::HashMap iterators * [core] add prelude trait impls for crypto hashers * [core] add unit test for storage::HashMap::iter * [core] remove outdated doc comment line * [core] add doc comments to fowarding-to-packed utility functions * [core] add some high-level documentation for some root storage2 modules * [core] add some more high-level docs * [core] add return value to storage::Stash::defrag The returned value tells the caller how many storage cells have actually been freed by the routine. * [core] add return value to storage::HashMap::defrag * [core] add unit test for storage::HashMap::{values, values_mut} Also add tests for Iterator::size_hint impls. * [core] add tests for Iterator::size_hint impls of storage::Vec * [core] add unit test for storage::HashMap::keys * [core] add unit test for storage::HashMap::defrag * [core] add unit tests for LazyIndexMap * [core] remove lazy::Entry::take_value * [core] remove LazyIndexMap::take * [core] remove Entry::set_state Uses have been replaced with Entry::replace_state. * [core] remove Lazy{Array, HashMap}::take method Replace uses with Lazy{Array, HashMap}::put_get(.., None) * [core] add unit test for LazyIndexMap::put * [core] add unit test for LazyIndexMap::swap * [core] apply rustfmt * [core] cover Default impl of LazyIndexMap with unit test * [core] move imports to top for LazyIndexMap .rs file * [core] refactor lazy::Entry internals a bit * [core] add unit tests for Index impl of storage::Vec * [core] add unit tests for Index impl of storage::SmallVec * [core] add tests for Index impl of StorageStash * [core] improve panic message for Index{Mut} impl of storage::Stash * [core] add unit tests for Index{Mut} impl of storage::Stash * [core] extend unit test for storage::Stash::get * [core] disable certain tests in --release mode testing * [core] add unit test for LazyIndexMap::{get, get_mut} * [core] add some unit tests for LazyArray * [core] add some more unit tests for LazyArray * [core] add some more unit tests to LaryArray * [core] apply rustfmt * [core] add unit tests for LazyCell * [core] add unit test for SpreadLayout impl of LazyCell * [core] extend SpreadLayout test for LazyCell * [core] extend SpreadLayout test to also cover the clear_spread impl * [core] rename unit test for LazyCell * [core] fix clippy warning * [core] fix some LazyCell cache entry in lazy form * [core] add new unit test for Debug impl of lazy initialized LazyCell * [core] add more unit tests for lazily initialized LazyCell * [core] implement shallow clean-up of storage via LazyCell * [core] test that a lazily loaded LazyCell preserves its cached value * [core] apply rustfmt * [core] add additional check for LazyCell cache preservation * [core] fix bug in LazyIndexMap::clear_packed_at * [core] add unit test for SpreadLayout impl of LazyIndexMap * [core] fix bug in LazyArray::clear_packed_at * [core] add unit test for SpreadLayout impl of LazyArray * [core] make LazyArray::capacity and SmallVec::capcity more user friendly * [core] remove unnecessary trait bounds * [core] remove more unnecessary trait bounds * [core] add initial unit test for LazyHashMap * [core] add unit test for LazyHashMap::key_at * [core] apply rustfmt * [core] indent a block in test * [core] add unit test for LazyHashMap::put_get * [core] add unit test for LazyHashMap::{get, get_mut} * [core] add unit test for LazyHashMap::put * [core] add unit test for LazyHashMap::swap * [core] make hash builders reset their accumulator upon finalization * [core] add unit test for SpreadLayout impl of LazyHashMap * [core] fix unit test for LazyHashMap::key_at Also add prefix to hash-key calculation. * [core] add unit tests for SpreadLayout impl of storage::Vec * [core] add unit tests for SpreadLayout impl of storage::SmallVec * [core] add unit tests for SpreadLayout impl of storage::Stash * [core] apply rustfmt * [core] add unit tests for SpreadLayout impl of storage::HashMap * [core] add unit test for DynamicAllocation::key * [core] add unit tests for SpreadLayout impl of storage::Bitvec * [core] fix LazyCell::get unit test * [core] remove unused dependencies from Cargo.toml * [core] add missing docs for storage::{Stash, HashMap} * [core] deny missing docs of public items * [core] add Debug impl to storage::Box * [core] add unit tests for storage::Box * [core] remove internal Pack::{get, get_mut} methods * [core] fix bug in storage::Memory::{get, get_mut} API * [core] add unit tests for storage::Pack * [core] improve storage::Pack unit tests * [core] experimental inline(never) for debug_assertions compilation * [core] apply rustfmt * [core] remove experimental #[inline(never)] * [core] add unit test for Default impl of storage::Pack * [core] add unit tests for storage::Memory * [core] fix a unit test for storage::Box The storage::Box tests did not reset the dynamic storage allocator instance in between their runs which caued them to have side effects on to each other if run single threaded. * [core] fix minor bug in BitRefMut utility of storage::Bitvec * [core] cover storage::Bitvec::get_mut in get_works unit test * [core] add unit tests for BitRefMut utility of storage::Bitvec * [core] apply rustfmt * [core] improve panic message when encountering a double free * [core] adjust double free unit test for storage::Box * [core] improve double free of dynamic storage panic message * [core] apply rustfmt * [core] merge Bits256Ref and Bits256RefMut into ChunkRef<T> * [core] split access.rs into bitref.rs and bitsref.rs * [core] apply rustfmt * [core] replace transmute with pointer cast Thanks clippy! * [core] add comment to explain repr(C) * [core] add PartialEq and Eq impls to BitRefMut * [core] add unit tests for ChunkRef * [core] add failure unit tests for dynamic storage allocator * [core] fix bug in SpreadLayout impl of Option<T> * [core] add unit test for dynamic storage allocator SpreadLayout impl * [core] fix SpreadLayout impl for Result<T, E> * [core] fix yet another bug in SpreadLayout impl of Result<T, E> * [core] move forward_supported_array_lens macro to usage site * [core] refactor some code duplication with clear_spread_root_opt * [core] fix doc comment in storage::Pack * [core] remove some unused unsafe blocks They are going to be re-introduced once the unsafe_op_in_unsafe_fn lint has been implemented in the Rust compiler. * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * [core] remove usage of storage::Pack in dynamic storage allocator * [core] improve panic message in Lazy::{get, get_mut} * [core] add test for SpreadLayout::clear_spread impl of dynamic storage alloc * [core] remove code dupe * [core] refactor clear_spread_root_opt utility function * [core] implement SpreadLayout::REQUIRES_DEEP_CLEAN_UP for some types * [core] move from bool to u8 for Option and Result SpreadLayout impls * [core] fix bug in SpreadLayout impl for Option * fix typo Co-authored-by: Andrew Jones <[email protected]> * [core] update LazyCell SAFETY comment * [core] update Entry docs * [core] remove unneeded code in lazy::Entry::pull_packed_root * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * [core] remove commented out code * [core] add new unit test for dynamic storage allocator * [core] refactor global storage allocator initialization routines * [core] fix Wasm compilation errors * [core] apply rustfmt * [core] surpress bad clippy lint * [core] remove dead code * [core] improve call_setup_works test * [core] fix bug in initialize_for for off-chain env * [core] initial steps to factor out BitStash from DynamicAllocator * [core] apply rustfmt * [core] add Derive impl for BitStash * [core] make use of storage::BitStash from dynamic storage allocator * [core] add unit tests for storage::BitStash * [core] apply rustfmt * [core] remove invalid TODO comment * [core] fix some out of bounds panic messages * [core] remove deliberate memory leak in test suite * [core] fix build failure for Wasm target * [core] add unit tests for SpreadLayout & PackedLayout impls of primitives * [core] add unit tests for packed layout explicitely * Fix some typos * Add simple double ended iter test * typos * comment typos * split hashmap to hash map in comments * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo in unreachable! message Co-authored-by: Andrew Jones <[email protected]> * fix typo in expects message Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> * [core] add more comments to storage2::HashMap::defrag * [core] make early return for storage2::HashMap::defrag for limit = 0 * [core] improve storage2::HashMap::contains_key implementation * [core] rename new_vec_works test to new_works * [core] apply Andrew's suggestions (and more) * [core] fix typo: increase -> decrease * [core] add panic to Bitvec::push in case it reached its maximum capacity * [core] update comments for storage bit stash * [core] add more explanation comments * [core] some more renamings of test internals * improve reasoning Co-authored-by: Andrew Jones <[email protected]> * fix typo Co-authored-by: Andrew Jones <[email protected]> Co-authored-by: Andrew Jones <[email protected]>
1 parent 1808550 commit dffc8cf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+14600
-16
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
[f2]: https://paritytech.github.io/ink/ink_core
1717
[h1]: https://img.shields.io/badge/docs-abi-blue.svg
1818
[h2]: https://paritytech.github.io/ink/ink_abi
19+
[i1]: https://img.shields.io/badge/docs-prelude-blue.svg
20+
[i2]: https://paritytech.github.io/ink/ink_prelude
1921

2022
**IMPORTANT NOTE:** WORK IN PROGRESS! Do not expect this to be working.
2123

@@ -25,9 +27,9 @@ For more information please visit [the ink! tutorial](https://substrate.dev/subs
2527

2628
## Developer Documentation
2729

28-
| `ink_abi` | `ink_core` |
29-
| ------------- | ------------- |
30-
| [![][h1]][h2] | [![][f1]][f2] |
30+
| `ink_abi` | `ink_core` | `ink_prelude` |
31+
| ------------- | ------------- | ------------- |
32+
| [![][h1]][h2] | [![][f1]][f2] | [![][i1]][i2] |
3133

3234
### Interaction with Substrate
3335

core/Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ ink_prelude = { version = "2.1.0", path = "../prelude/", default-features = fals
2323

2424
scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
2525
derive_more = { version = "0.99", default-features = false, features = ["from", "display"] }
26-
smallvec = { version = "1.2", default-features = false, features = ["union"] }
27-
cfg-if = "0.1"
2826
num-traits = { version = "0.2", default-features = false, features = ["i128"] }
27+
cfg-if = "0.1"
28+
array-init = "0.1"
29+
generic-array = "0.14.1"
2930
paste = "0.1"
3031

3132
# Hashes for the off-chain environment.
32-
byteorder = { version = "1.3", optional = true }
3333
blake2-rfc = { version = "0.2", optional = true }
3434
sha2 = { version = "0.8", optional = true }
3535
tiny-keccak = { version = "2.0", optional = true }
@@ -63,7 +63,6 @@ std = [
6363
"rand/std",
6464
"num-traits/std",
6565
# Enables hashing crates for off-chain environment.
66-
"byteorder",
6766
"blake2-rfc",
6867
"sha2",
6968
"tiny-keccak",

core/src/env/call/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ mod builder;
1818
mod instantiate;
1919
mod utils;
2020

21+
/// The compile-time states of builder for calls and instantiations.
22+
#[doc(hidden)]
2123
pub mod state {
2224
pub use crate::env::call::{
2325
instantiate::state::{

core/src/env/engine/off_chain/test_api.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,17 @@ pub struct DefaultAccounts<T>
257257
where
258258
T: EnvTypes,
259259
{
260+
/// The predefined `ALICE` account holding substantial amounts of value.
260261
pub alice: T::AccountId,
262+
/// The predefined `BOB` account holding some amounts of value.
261263
pub bob: T::AccountId,
264+
/// The predefined `CHARLIE` account holding some amounts of value.
262265
pub charlie: T::AccountId,
266+
/// The predefined `DJANGO` account holding no value.
263267
pub django: T::AccountId,
268+
/// The predefined `EVE` account holding no value.
264269
pub eve: T::AccountId,
270+
/// The predefined `FRANK` account holding no value.
265271
pub frank: T::AccountId,
266272
}
267273

core/src/hash/builder.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,22 @@ pub trait Finalize<H>
111111
where
112112
H: Hasher,
113113
{
114-
fn finalize_using(&self, output: &mut <H as Hasher>::Output);
115-
fn finalize(&self) -> <H as Hasher>::Output;
114+
fn finalize_using(&mut self, output: &mut <H as Hasher>::Output);
115+
fn finalize(&mut self) -> <H as Hasher>::Output;
116116
}
117117

118118
impl<H, S> Finalize<H> for HashBuilder<H, S>
119119
where
120120
H: Hasher,
121121
S: Accumulator,
122122
{
123-
fn finalize_using(&self, output: &mut <H as Hasher>::Output) {
124-
<H as Hasher>::finalize_immediate(self.strategy.as_slice(), output)
123+
fn finalize_using(&mut self, output: &mut <H as Hasher>::Output) {
124+
let output = <H as Hasher>::finalize_immediate(self.strategy.as_slice(), output);
125+
self.strategy.reset();
126+
output
125127
}
126128

127-
fn finalize(&self) -> <H as Hasher>::Output {
129+
fn finalize(&mut self) -> <H as Hasher>::Output {
128130
let mut output = <<H as Hasher>::Output as Default>::default();
129131
Self::finalize_using(self, &mut output);
130132
output

core/src/hash/hasher.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ macro_rules! impl_hasher_for {
3434
struct $ty_name:ident($fn_name:ident, $output_len:literal);
3535
) => {
3636
$( #[$doc] )*
37+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3738
pub enum $ty_name {}
3839

3940
impl Hasher for $ty_name {
@@ -47,21 +48,17 @@ macro_rules! impl_hasher_for {
4748
}
4849
impl_hasher_for! {
4950
/// SHA2 256-bit hasher.
50-
#[derive(Debug)]
5151
struct Sha2x256Hasher(sha2_256, 32);
5252
}
5353
impl_hasher_for! {
5454
/// KECCAK 256-bit hasher.
55-
#[derive(Debug)]
5655
struct Keccak256Hasher(keccak_256, 32);
5756
}
5857
impl_hasher_for! {
5958
/// BLAKE2 256-bit hasher.
60-
#[derive(Debug)]
6159
struct Blake2x256Hasher(blake2_256, 32);
6260
}
6361
impl_hasher_for! {
6462
/// BLAKE2 128-bit hasher.
65-
#[derive(Debug)]
6663
struct Blake2x128Hasher(blake2_128, 16);
6764
}

core/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
2323
#![cfg_attr(not(feature = "std"), no_std)]
2424
#![deny(
25+
missing_docs,
2526
bad_style,
27+
bare_trait_objects,
2628
const_err,
2729
improper_ctypes,
2830
non_shorthand_field_patterns,
@@ -49,6 +51,7 @@ extern crate ink_alloc;
4951
pub mod env;
5052
pub mod hash;
5153
pub mod storage;
54+
pub mod storage2;
5255

5356
// Needed for derive macros of `core/derive` sub crate.
5457
pub(crate) use crate as ink_core;

core/src/storage2/alloc/allocation.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use crate::hash::{
16+
Blake2x256,
17+
Wrap,
18+
};
19+
use ink_primitives::Key;
20+
21+
/// A unique dynamic allocation.
22+
///
23+
/// This can refer to a dynamically allocated storage cell.
24+
/// It has been created by a dynamic storage allocator.
25+
/// The initiator of the allocation has to make sure to deallocate
26+
/// this dynamic allocation again using the same dynamic allocator
27+
/// if it is no longer in use.
28+
///
29+
/// # Note
30+
///
31+
/// Normally instances of this type are not used directly and instead
32+
/// a [`storage::Box`](`crate::storage2::Box`) is used instead.
33+
#[derive(
34+
Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, scale::Encode, scale::Decode,
35+
)]
36+
pub struct DynamicAllocation(pub(super) u32);
37+
38+
impl DynamicAllocation {
39+
/// Returns the allocation identifier as `u32`.
40+
pub(super) fn get(self) -> u32 {
41+
self.0
42+
}
43+
44+
/// Returns the storage key associated with this dynamic allocation.
45+
pub fn key(self) -> Key {
46+
// We create a 25-bytes buffer for the hashing.
47+
// This is due to the fact that we prepend the `u32` encoded identifier
48+
// with the `b"DYNAMICALLY ALLOCATED"` byte string which has a length
49+
// 21 bytes. Since `u32` always has an encoding length of 4 bytes we
50+
// end up requiring 25 bytes in total.
51+
// Optimization Opportunity:
52+
// Since ink! always runs single threaded we could make this buffer
53+
// static and instead reuse its contents with every invocation of this
54+
// method. However, this would introduce `unsafe` Rust usage.
55+
#[rustfmt::skip]
56+
let mut buffer: [u8; 25] = [
57+
b'D', b'Y', b'N', b'A', b'M', b'I', b'C', b'A', b'L', b'L', b'Y',
58+
b' ',
59+
b'A', b'L', b'L', b'O', b'C', b'A', b'T', b'E', b'D',
60+
b'_', b'_', b'_', b'_',
61+
];
62+
// Encode the `u32` identifier requires a 4 bytes buffer.
63+
let mut hash_buffer = Wrap::from(&mut buffer[21..25]);
64+
<u32 as scale::Encode>::encode_to(&self.0, &mut hash_buffer);
65+
let mut output = [0x00_u8; 32];
66+
<Blake2x256>::hash_bytes_using(&buffer, &mut output);
67+
Key::from(output)
68+
}
69+
}
70+
71+
#[test]
72+
fn get_works() {
73+
let expected_keys = [
74+
b"\
75+
\x0A\x0F\xF5\x30\xBD\x5A\xB6\x67\
76+
\x85\xC9\x74\x6D\x01\x33\xD7\xE1\
77+
\x24\x40\xC4\x67\xA9\xF0\x6D\xCA\
78+
\xE7\xED\x2E\x78\x32\x77\xE9\x10",
79+
b"\
80+
\x11\x5A\xC0\xB2\x29\xA5\x34\x10\
81+
\xB0\xC0\x2D\x47\x49\xDC\x7A\x09\
82+
\xB9\x6D\xF9\x51\xB6\x1D\x4F\x3B\
83+
\x4E\x75\xAC\x3B\x14\x57\x47\x96",
84+
];
85+
assert_eq!(DynamicAllocation(0).key(), Key(*expected_keys[0]));
86+
assert_eq!(DynamicAllocation(1).key(), Key(*expected_keys[1]));
87+
}

core/src/storage2/alloc/allocator.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use super::DynamicAllocation;
16+
use crate::storage2::{
17+
collections::BitStash,
18+
traits::{
19+
KeyPtr,
20+
SpreadLayout,
21+
},
22+
};
23+
24+
/// The dynamic allocator.
25+
///
26+
/// Manages dynamic storage allocations in a very efficient and economic way.
27+
#[derive(Debug, Default, PartialEq, Eq)]
28+
pub struct DynamicAllocator {
29+
allocations: BitStash,
30+
}
31+
32+
impl SpreadLayout for DynamicAllocator {
33+
const FOOTPRINT: u64 = <BitStash as SpreadLayout>::FOOTPRINT;
34+
35+
fn pull_spread(ptr: &mut KeyPtr) -> Self {
36+
Self {
37+
allocations: SpreadLayout::pull_spread(ptr),
38+
}
39+
}
40+
41+
fn push_spread(&self, ptr: &mut KeyPtr) {
42+
SpreadLayout::push_spread(&self.allocations, ptr);
43+
}
44+
45+
fn clear_spread(&self, ptr: &mut KeyPtr) {
46+
SpreadLayout::clear_spread(&self.allocations, ptr);
47+
}
48+
}
49+
50+
impl DynamicAllocator {
51+
/// Returns a new dynamic storage allocation.
52+
///
53+
/// # Panics
54+
///
55+
/// If the dynamic allocator ran out of free dynamic allocations.
56+
pub fn alloc(&mut self) -> DynamicAllocation {
57+
DynamicAllocation(self.allocations.put())
58+
}
59+
60+
/// Frees the given dynamic storage allocation.
61+
///
62+
/// This makes the given dynamic storage allocation available again
63+
/// for new dynamic storage allocations.
64+
///
65+
/// # Panics
66+
///
67+
/// Panics if the given dynamic allocation is invalid.
68+
/// A dynamic allocation is invalid if it is not represented as occupied
69+
/// in the `free` list.
70+
pub fn free(&mut self, allocation: DynamicAllocation) {
71+
let index = allocation.get();
72+
if !self
73+
.allocations
74+
.take(index)
75+
.expect("invalid dynamic storage allocation")
76+
{
77+
panic!(
78+
"encountered double free of dynamic storage: at index {}",
79+
index
80+
)
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)