cairo-native 0.9.0-rc.3

A compiler to convert Cairo's IR Sierra code to MLIR and execute it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
//! Storage-related types and traits for Cairo contracts.
//!
//! This module implements the storage system for Starknet contracts, providing high-level
//! abstractions for persistent data storage. It offers a type-safe interface for reading and
//! writing to Starknet storage through the [`StoragePointerReadAccess`] and
//! [`StoragePointerWriteAccess`] traits, along with useful storage-only collection types like
//! [`Vec`] and [`Map`].
//!
//! [`Vec`]: starknet::storage::vec::Vec
//! [`Map`]: starknet::storage::map::Map
//!
//! # Overview
//!
//! The storage system in Starknet contracts is built on a key-value store where each storage slot
//! is identified by a 251-bit address. The storage system allows interactions with storage using
//! state variables, which are declared inside a `Storage` struct annotated with the `#[storage]`
//! attribute. This ensures type-safe storage access and simplifies the process of reading and
//! writing to storage.
//!
//! # Using the Storage System
//!
//! Storage is typically declared using the `#[storage]` attribute on a struct:
//!
//! ```
//! #[storage]
//! struct Storage {
//!     balance: u256,
//!     users: Map<ContractAddress, User>,
//!     nested_data: Map<ContractAddress, Map<ContractAddress, u8>>,
//!     collection: Vec<u8>,
//! }
//! ```
//!
//! Any type that implements the `Store` trait (or its optimized `StorePacked` variant) can be used
//! in storage.  This type can simply be derived using `#[derive(Store)]` - provided that all of the
//! members of the type also implement `Store`.
//!
//! ```
//! #[derive(Copy, Default, Drop, Store)]
//! struct User {
//!     name: felt252,
//!     age: u8,
//! }
//! ```
//!
//! Interaction with storage is made through a set of traits, depending on the type interacted
//! with:
//!
//! - [`StoragePointerReadAccess`] and [`StoragePointerWriteAccess`] allow for reading and writing
//! storable types.
//! - [`StorageMapReadAccess`] and [`StorageMapWriteAccess`] allow for reading and writing to
//! storage [`Map`]s.
//! - [`StoragePathEntry`] allows for accessing a specific entry in a [`Map`], and can be combined
//! with the `StoragePointer` traits to read and write in these entries.
//! - [`VecTrait`] and [`MutableVecTrait`] allow for interacting with storage [`Vec`]s.
//!
//! [`VecTrait`]: starknet::storage::vec::VecTrait
//! [`MutableVecTrait`]: starknet::storage::vec::MutableVecTrait
//! [`StorageMapReadAccess`]: starknet::storage::map::StorageMapReadAccess
//! [`StorageMapWriteAccess`]: starknet::storage::map::StorageMapWriteAccess
//! [`StoragePathEntry`]: starknet::storage::map::StoragePathEntry
//!
//! ## Examples
//!
//! ```
//! fn use_storage(self: @ContractState) {
//!     let address = 'address'.try_into().unwrap();
//!     // Reading values
//!     let balance = self.balance.read();
//!     // For a `Map`, use the `entry` method to access values at specific keys:
//!     let user = self.users.entry(address).read();
//!     // Accessing nested `Map`s requires chaining `entry` calls:
//!     let nested = self.nested_data.entry(address).entry(address).read();
//!     // Accessing a specific index in a `Vec` requires using the `index` method:
//!     let element = self.collection[index];
//!
//!     // Writing values
//!     self.balance.write(100);
//!     self.users.entry(address).write(Default::default());
//!     self.nested_data.entry(address).entry(address).write(10);
//!     self.collection[index].write(20);
//! }
//! ```
//!
//! # Storage Lifecycle
//!
//! When you access a storage variable, it goes through several transformations:
//!
//! 1. **FlattenedStorage**: The starting point is your contract's storage struct. Each member is
//!    represented either as a `StorageBase` or another `FlattenedStorage` (for `#[substorage(v0)]`
//!    or `#[flat]` members).
//!
//! 2. **StorageBase**: For simple variables, this holds the `sn_keccak` hash of the variable name,
//!    which becomes the storage address. For example:
//!    ```
//!    #[storage]
//!    struct Storage {
//!        balance: u128,  // Stored at sn_keccak('balance')
//!    }
//!    ```
//! 3. **StoragePath**: For complex types, a `StoragePath` represents an un-finalized path to a
//!     specific entry in storage. For example, a `StoragePath` for a `Map` can be updated with
//!     specific keys to point to a specific entry in the map.
//!
//! 4. **StoragePointer**: The final form, pointing to the actual storage location. For multi-slot
//!    values (like structs), values are stored sequentially from this address.
//!
//! # Storage Collections
//!
//! Cairo's memory collection types, like [`Felt252Dict`] and [`Array`], cannot be used in storage.
//! Consequently, any type that contains these types cannot be used in storage either.
//! Instead, Cairo has two storage-only collection types: [`Map`] and [`Vec`].
//!
//! Instead of storing these _memory_ collections directly, you will need to reflect them into
//! storage using the [`Map`] and [`Vec`] types.
//!
//! # Address Calculation
//!
//! Storage addresses are calculated deterministically:
//!
//! * For a single value variable, the address is the `sn_keccak` hash of the variable name's ASCII
//! encoding. `sn_keccak` is Starknet's version of the Keccak-256 hash function, with its output
//! truncated to 250 bits.
//!
//! * For variables composed of multiple values (tuples, structs, or enums), the base storage
//! address is also the `sn_keccak` hash of the variable name's ASCII encoding. The storage layout
//! then varies depending on the specific type. A struct will store its members as a sequence of
//! primitive types, while an enum will store its variant index, followed by the members of the
//! variant.
//!
//! * For variables within a storage node, the address is calculated using a chain of hashes that
//! represents the node structure. Given a member `m` within a storage variable `variable_name`,
//! the path is computed as `h(sn_keccak(variable_name), sn_keccak(m))`, where `h` is the Pedersen
//! hash. For nested storage nodes, this process repeats, creating a hash chain representing the
//! path to each leaf node. At the leaf node, the storage calculation follows the standard rules for
//! that variable type.
//!
//! * For [`Map`] or [`Vec`] variables, the address is calculated relative to the storage base
//! address (the `sn_keccak` hash of the variable name) combined with the mapping keys or vector
//! indices.
//! See their respective module documentation for more details.
use core::hash::HashStateTrait;
#[allow(unused_imports)]
use core::pedersen::HashState;
use core::traits::Into;
#[allow(unused_imports)]
use starknet::SyscallResult;
use starknet::storage_access::{StorageBaseAddress, storage_base_address_from_felt252};

mod map;
pub use map::{Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry};

mod storage_base;
pub use storage_base::{FlattenedStorage, StorageBase, StorageTrait, StorageTraitMut};

mod storage_node;
pub use storage_node::{StorageNode, StorageNodeMut};

mod sub_pointers;
pub use sub_pointers::{SubPointers, SubPointersForward, SubPointersMut, SubPointersMutForward};

mod vec;
use vec::{
    MutableVecIndexView, MutableVecIntoIterRange, PathableMutableVecIntoIterRange,
    PathableVecIntoIterRange, VecIndexView, VecIntoIterRange,
};
pub use vec::{MutableVecTrait, Vec, VecIter, VecTrait};

/// A pointer to an address in storage, can be used to read and write values, if the generic type
/// supports it (e.g. basic types like `felt252`).
pub struct StoragePointer<T> {
    pub __storage_pointer_address__: StorageBaseAddress,
    pub __storage_pointer_offset__: u8,
}

impl StoragePointerCopy<T> of Copy<StoragePointer<T>> {}
impl StoragePointerDrop<T> of Drop<StoragePointer<T>> {}

/// This makes the sub-pointers members directly accessible from a pointer to the parent struct.
pub impl SubPointersDeref<T, +SubPointers<T>> of core::ops::Deref<StoragePointer<T>> {
    type Target = SubPointers::<T>::SubPointersType;
    fn deref(self: StoragePointer<T>) -> Self::Target {
        self.sub_pointers()
    }
}

/// This makes the sub-pointers members directly accessible from a pointer to the parent struct.
pub impl SubPointersMutDeref<
    T, +SubPointersMut<T>,
> of core::ops::Deref<StoragePointer<Mutable<T>>> {
    type Target = SubPointersMut::<T>::SubPointersType;
    fn deref(self: StoragePointer<Mutable<T>>) -> Self::Target {
        self.sub_pointers_mut()
    }
}


/// Same as `StoragePointer`, but with `offset` 0, which allows for some optimizations.
pub struct StoragePointer0Offset<T> {
    pub __storage_pointer_address__: StorageBaseAddress,
}

impl StoragePointer0OffsetCopy<T> of Copy<StoragePointer0Offset<T>> {}
impl StoragePointer0OffsetDrop<T> of Drop<StoragePointer0Offset<T>> {}

/// Trait for converting a storage member to a `StoragePointer0Offset`.
// type instead of `T`.
pub trait StorageAsPointer<TMemberState> {
    type Value;
    fn as_ptr(self: @TMemberState) -> StoragePointer0Offset<Self::Value>;
}

/// Trait for accessing the values in storage using a `StoragePointer`.
///
/// # Examples
///
//! ```
//! use starknet::storage::StoragePointerReadAccess;
//!
//! #[storage]
//! struct Storage {
//!     element: felt252,
//! }
//!
//! fn read_storage(self: @ContractState) -> felt252 {
//!     self.element.read()
//! }
//! ```
pub trait StoragePointerReadAccess<T> {
    type Value;
    fn read(self: @T) -> Self::Value;
}

/// Trait for writing values to storage using a `StoragePointer`.
///
/// # Examples
///
//! ```
//! use starknet::storage::StoragePointerWriteAccess;
//!
//! #[storage]
//! struct Storage {
//!     element: felt252,
//! }
//!
//! fn write_storage(self: @ContractState) {
//!     self.element.write(1);
//! }
//! ```
pub trait StoragePointerWriteAccess<T> {
    type Value;
    fn write(self: T, value: Self::Value);
}

/// Simple implementation of `StoragePointerReadAccess` for any type that implements `Store` for 0
/// offset.
impl StorableStoragePointer0OffsetReadAccess<
    T, +starknet::Store<T>,
> of StoragePointerReadAccess<StoragePointer0Offset<T>> {
    type Value = T;
    fn read(self: @StoragePointer0Offset<T>) -> T {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<T>::read(0, self.__storage_pointer_address__),
        )
    }
}

/// Simple implementation of `StoragePointerReadAccess` for any mutable type that implements `Store`
/// for 0 offset.
impl MutableStorableStoragePointer0OffsetReadAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>,
> of StoragePointerReadAccess<StoragePointer0Offset<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn read(self: @StoragePointer0Offset<T>) -> MutableTrait::<T>::InnerType {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType,
            >::read(0, self.__storage_pointer_address__),
        )
    }
}

/// Simple implementation of `StoragePointerWriteAccess` for any mutable type that implements
/// `Store` for 0 offset.
impl StorableStoragePointer0OffsetWriteAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>,
> of StoragePointerWriteAccess<StoragePointer0Offset<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn write(self: StoragePointer0Offset<T>, value: MutableTrait::<T>::InnerType) {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType,
            >::write(0, self.__storage_pointer_address__, value),
        )
    }
}

/// Simple implementation of `StoragePointerReadAccess` for any type that implements `Store` for any
/// offset.
pub impl StorableStoragePointerReadAccess<
    T, +starknet::Store<T>,
> of StoragePointerReadAccess<StoragePointer<T>> {
    type Value = T;
    fn read(self: @StoragePointer<T>) -> T {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                T,
            >::read_at_offset(0, self.__storage_pointer_address__, self.__storage_pointer_offset__),
        )
    }
}

/// Simple implementation of `StoragePointerReadAccess` for any mutable type that implements `Store`
/// for any offset.
impl MutableStorableStoragePointerReadAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>,
> of StoragePointerReadAccess<StoragePointer<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn read(self: @StoragePointer<T>) -> MutableTrait::<T>::InnerType {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType,
            >::read_at_offset(0, self.__storage_pointer_address__, self.__storage_pointer_offset__),
        )
    }
}

/// Simple implementation of `StoragePointerWriteAccess` for any mutable type that implements
/// `Store` for any offset.
impl MutableStorableStoragePointerWriteAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>,
> of StoragePointerWriteAccess<StoragePointer<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn write(self: StoragePointer<T>, value: MutableTrait::<T>::InnerType) {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType,
            >::write_at_offset(
                0, self.__storage_pointer_address__, self.__storage_pointer_offset__, value,
            ),
        )
    }
}

/// An intermediate struct to store a hash state, in order to be able to hash multiple values and
/// get the final address.
/// Storage path should have two interfaces, if `T` is storable then it should implement
/// `StorageAsPointer` in order to be able to get the address of the storage path. Otherwise, if
/// `T` is not storable then it should implement some kind of updating trait, e.g.
/// `StoragePathEntry`.
pub struct StoragePath<T> {
    __hash_state__: StoragePathHashState,
}

/// The hash state of a storage path.
type StoragePathHashState = core::pedersen::HashState;

impl StoragePathCopy<T> of core::traits::Copy<StoragePath<T>> {}
impl StoragePathDrop<T> of core::traits::Drop<StoragePath<T>> {}

/// This makes the storage node members directly accessible from a path to the parent struct.
pub impl StorageNodeDeref<T, +StorageNode<T>> of core::ops::Deref<StoragePath<T>> {
    type Target = StorageNode::<T>::NodeType;
    fn deref(self: StoragePath<T>) -> Self::Target {
        self.storage_node()
    }
}

/// This makes the storage node members directly accessible from a path to the parent struct.
pub impl StorageNodeMutDeref<T, +StorageNodeMut<T>> of core::ops::Deref<StoragePath<Mutable<T>>> {
    type Target = StorageNodeMut::<T>::NodeType;
    fn deref(self: StoragePath<Mutable<T>>) -> Self::Target {
        self.storage_node_mut()
    }
}

/// Trait for StoragePath operations.
trait StoragePathTrait<T> {
    fn new(init_value: felt252) -> StoragePath<T>;
    fn finalize(self: StoragePath<T>) -> StorageBaseAddress;
}

impl StoragePathImpl<T> of StoragePathTrait<T> {
    fn new(init_value: felt252) -> StoragePath<T> {
        StoragePath { __hash_state__: core::pedersen::PedersenTrait::new(init_value) }
    }

    fn finalize(self: StoragePath<T>) -> StorageBaseAddress {
        storage_base_address_from_felt252(self.__hash_state__.finalize())
    }
}

/// Trait for updating the hash state of a storage path with a given value. Also changes the generic
/// type of the storage path from `SourceType` to `TargetType`.
trait StoragePathUpdateTrait<SourceType, TargetType, Value> {
    fn update(self: StoragePath<SourceType>, value: Value) -> StoragePath<TargetType>;
}

impl StoragePathUpdateImpl<
    SourceType, TargetType, Value, impl HashImpl: core::hash::Hash<Value, StoragePathHashState>,
> of StoragePathUpdateTrait<SourceType, TargetType, Value> {
    fn update(self: StoragePath<SourceType>, value: Value) -> StoragePath<TargetType> {
        StoragePath { __hash_state__: HashImpl::update_state(self.__hash_state__, value) }
    }
}

impl StoragePathSIntoStoragePathTImpl<
    SourceType, TargetType,
> of Into<StoragePath<SourceType>, StoragePath<TargetType>> {
    fn into(self: StoragePath<SourceType>) -> StoragePath<TargetType> {
        StoragePath { __hash_state__: self.__hash_state__ }
    }
}

/// Trait for creating a new `StoragePath` from a storage member.
pub trait StorageAsPath<TMemberState> {
    type Value;
    fn as_path(self: @TMemberState) -> StoragePath<Self::Value>;
}

/// An implementation of `StorageAsPointer` for any `StoragePath` with inner type that implements
/// `Store`.
impl StorableStoragePathAsPointer<T, +starknet::Store<T>> of StorageAsPointer<StoragePath<T>> {
    type Value = T;
    fn as_ptr(self: @StoragePath<T>) -> StoragePointer0Offset<T> {
        StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() }
    }
}

/// An implementation of `StorageAsPointer` for any `StoragePath` with inner type that implements
/// `Store`.
impl MutableStorableStoragePathAsPointer<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>,
> of StorageAsPointer<StoragePath<T>> {
    type Value = T;
    fn as_ptr(self: @StoragePath<T>) -> StoragePointer0Offset<T> {
        StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() }
    }
}

/// Implement `Deref` for storage paths that implements `StorageAsPointer`.
impl StoragePathDeref<
    T, impl PointerImpl: StorageAsPointer<StoragePath<T>>,
> of core::ops::Deref<StoragePath<T>> {
    type Target = StoragePointer0Offset<PointerImpl::Value>;
    fn deref(self: StoragePath<T>) -> StoragePointer0Offset<PointerImpl::Value> {
        self.as_ptr()
    }
}

/// Implement `Deref` for `StoragePointer0Offset` into a `StoragePointer`.
impl StoragePointer0OffsetDeref<T> of core::ops::Deref<StoragePointer0Offset<T>> {
    type Target = StoragePointer<T>;
    fn deref(self: StoragePointer0Offset<T>) -> StoragePointer<T> {
        StoragePointer::<
            T,
        > {
            __storage_pointer_address__: self.__storage_pointer_address__,
            __storage_pointer_offset__: 0,
        }
    }
}

/// A struct for delaying the creation of a storage path, used for lazy evaluation in storage nodes.
pub struct PendingStoragePath<T> {
    __hash_state__: StoragePathHashState,
    __pending_key__: felt252,
}

/// A trait for creating a `PendingStoragePath` from a `StoragePath` hash state and a key.
pub trait PendingStoragePathTrait<T, S> {
    fn new(storage_path: @StoragePath<S>, pending_key: felt252) -> PendingStoragePath<T>;
}

impl PendingStoragePathImpl<T, S> of PendingStoragePathTrait<T, S> {
    fn new(storage_path: @StoragePath<S>, pending_key: felt252) -> PendingStoragePath<T> {
        PendingStoragePath {
            __hash_state__: storage_path.__hash_state__, __pending_key__: pending_key,
        }
    }
}

impl PendingStoragePathDrop<T> of Drop<PendingStoragePath<T>> {}
impl PendingStoragePathCopy<T> of Copy<PendingStoragePath<T>> {}

/// An implementation of 'StorageAsPath' for `PendingStoragePath`.
impl PendingStoragePathAsPath<T> of StorageAsPath<PendingStoragePath<T>> {
    type Value = T;
    fn as_path(self: @PendingStoragePath<T>) -> StoragePath<T> {
        StoragePath::<
            T,
        > {
            __hash_state__: core::hash::HashStateTrait::update(
                self.__hash_state__, self.__pending_key__,
            ),
        }
    }
}

/// Deref pending storage path into a storage path.
impl PendingStoragePathDeref<T> of core::ops::Deref<PendingStoragePath<T>> {
    type Target = StoragePath<T>;
    fn deref(self: PendingStoragePath<T>) -> Self::Target {
        self.as_path()
    }
}

/// Implement as_ptr for any type that implements StorageAsPath and Store.
impl StorablePathableStorageAsPointer<
    T,
    impl PathImpl: StorageAsPath<T>,
    impl PtrImpl: StorageAsPointer<StoragePath<PathImpl::Value>>,
> of StorageAsPointer<T> {
    type Value = PtrImpl::Value;
    fn as_ptr(self: @T) -> StoragePointer0Offset<PtrImpl::Value> {
        let path = self.as_path();
        path.as_ptr()
    }
}

/// Implement StoragePointerReadAccess for any type that implements StorageAsPointer and
/// StoragePointerReadAccess.
impl StorablePointerReadAccessImpl<
    T,
    impl PointerImpl: StorageAsPointer<T>,
    impl AccessImpl: StoragePointerReadAccess<StoragePointer0Offset<PointerImpl::Value>>,
> of StoragePointerReadAccess<T> {
    type Value = AccessImpl::Value;
    fn read(self: @T) -> Self::Value {
        self.as_ptr().read()
    }
}

/// Implement StoragePointerWriteAccess for any type that implements StorageAsPointer.
impl StorablePointerWriteAccessImpl<
    T,
    impl PointerImpl: StorageAsPointer<T>,
    impl AccessImpl: StoragePointerWriteAccess<StoragePointer0Offset<PointerImpl::Value>>,
    +Drop<T>,
    +Drop<AccessImpl::Value>,
> of StoragePointerWriteAccess<T> {
    type Value = AccessImpl::Value;
    fn write(self: T, value: Self::Value) {
        let ptr: StoragePointer0Offset<PointerImpl::Value> = self.as_ptr();
        ptr.write(value)
    }
}

/// A wrapper around different storage related types, indicating that the instance is mutable,
/// i.e. originally created from a `ref` contract state.
#[phantom]
pub struct Mutable<T> {}

impl MutableDrop<T> of Drop<Mutable<T>> {}
impl MutableCopy<T> of Copy<Mutable<T>> {}


/// A trait for exposing the inner type of a `Mutable` type.
trait MutableTrait<T> {
    type InnerType;
}

impl MutableImpl<T> of MutableTrait<Mutable<T>> {
    type InnerType = T;
}

pub trait StoragePathMutableConversion<T> {
    /// Converts a `StoragePath<Mutable<T>>` to a `StoragePath<T>`. This is useful to expose
    /// functions implemented for `StoragePath<T>` on a `StoragePath<Mutable<T>>`.
    fn as_non_mut(self: StoragePath<Mutable<T>>) -> StoragePath<T>;
}


impl StoragePathAsNonMutImpl<T> of StoragePathMutableConversion<T> {
    fn as_non_mut(self: StoragePath<Mutable<T>>) -> StoragePath<T> {
        StoragePath { __hash_state__: self.__hash_state__ }
    }
}


/// Trait for turning collection of values into an iterator over a specific range.
pub trait IntoIterRange<T> {
    type IntoIter;
    impl Iterator: Iterator<Self::IntoIter>;
    /// Creates an iterator over a range from a collection.
    fn into_iter_range(self: T, range: core::ops::Range<u64>) -> Self::IntoIter;
    /// Creates an iterator over the full range of a collection.
    fn into_iter_full_range(self: T) -> Self::IntoIter;
}

/// Trait that ensures a type is valid for storage in Starknet contracts.
/// This trait is used to enforce that only specific types, such as those implementing
/// `Store` or acting as a `StorageNode`, can be a part of a storage hierarchy. Any type
/// that does not implement this trait cannot be used in a storage struct.
pub trait ValidStorageTypeTrait<T>;

/// Implementation of `ValidStorageTypeTrait` for types that implement `starknet::Store`.
impl ValidStorageTypeTraitStoreImpl<T, +starknet::Store<T>> of ValidStorageTypeTrait<T>;

/// `StorageTrait` is typically used for storage nodes, which help organize contract storage
/// hierarchies. By implementing `ValidStorageTypeTrait`, this ensures that storage nodes (and
/// substorages within components) are valid storage types.
impl ValidStorageTypeTraitStorageNodeImpl<T, +StorageTrait<T>> of ValidStorageTypeTrait<T>;