ink_storage_traits/impls/
mod.rs1use crate::{
16 AutoStorableHint,
17 Packed,
18 StorableHint,
19 StorageKey,
20};
21use core::{
22 fmt::Debug,
23 marker::PhantomData,
24};
25use ink_primitives::{
26 Key,
27 KeyComposer,
28};
29
30trait KeyType {
32 const IS_AUTO_KEY: bool;
36}
37
38#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd)]
40#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
41pub struct AutoKey;
42
43impl StorageKey for AutoKey {
44 const KEY: Key = 0;
45}
46
47impl KeyType for AutoKey {
48 const IS_AUTO_KEY: bool = true;
49}
50
51impl Debug for AutoKey {
52 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
53 f.debug_struct("AutoKey")
54 .field("key", &<Self as StorageKey>::KEY)
55 .finish()
56 }
57}
58
59#[derive(Default, Copy, Clone, Eq, PartialEq, PartialOrd)]
61#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
62pub struct ManualKey<const KEY: Key, ParentKey: StorageKey = ()>(
63 PhantomData<fn() -> ParentKey>,
64);
65
66impl<const KEY: Key, ParentKey: StorageKey> StorageKey for ManualKey<KEY, ParentKey> {
67 const KEY: Key = KeyComposer::concat(KEY, ParentKey::KEY);
68}
69
70impl<const KEY: Key, ParentKey: StorageKey> KeyType for ManualKey<KEY, ParentKey> {
71 const IS_AUTO_KEY: bool = false;
72}
73
74impl<const KEY: Key, ParentKey: StorageKey> Debug for ManualKey<KEY, ParentKey> {
75 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
76 f.debug_struct("ManualKey")
77 .field("key", &<Self as StorageKey>::KEY)
78 .finish()
79 }
80}
81
82#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
85#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
86pub struct ResolverKey<L, R>(PhantomData<fn() -> (L, R)>);
87
88impl<L, R> StorageKey for ResolverKey<L, R>
89where
90 L: StorageKey + KeyType,
91 R: StorageKey + KeyType,
92{
93 const KEY: Key = if L::IS_AUTO_KEY { R::KEY } else { L::KEY };
96}
97
98impl<L, R> KeyType for ResolverKey<L, R>
99where
100 L: KeyType,
101 R: KeyType,
102{
103 const IS_AUTO_KEY: bool = L::IS_AUTO_KEY;
107}
108
109type FinalKey<T, const KEY: Key, ParentKey> =
110 ResolverKey<<T as StorableHint<ParentKey>>::PreferredKey, ManualKey<KEY, ParentKey>>;
111
112impl<T, const KEY: Key, ParentKey> AutoStorableHint<ManualKey<KEY, ParentKey>> for T
118where
119 T: StorableHint<ParentKey>,
120 <T as StorableHint<ParentKey>>::PreferredKey: KeyType,
121 T: StorableHint<FinalKey<T, KEY, ParentKey>>,
122 ParentKey: StorageKey,
123{
124 type Type = <T as StorableHint<FinalKey<T, KEY, ParentKey>>>::Type;
125}
126
127impl<P> super::storage::private::Sealed for P where P: scale::Decode + scale::Encode {}
128#[diagnostic::do_not_recommend]
129impl<P> Packed for P where P: scale::Decode + scale::Encode {}
130
131impl<P> StorageKey for P
132where
133 P: Packed,
134{
135 const KEY: Key = 0;
136}
137
138impl<P, Key> StorableHint<Key> for P
139where
140 P: Packed,
141 Key: StorageKey,
142{
143 type Type = P;
144 type PreferredKey = AutoKey;
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[macro_export]
153 macro_rules! storage_hint_works_for_primitive {
154 ( $ty:ty ) => {
155 paste::item! {
156 #[test]
157 #[allow(non_snake_case)]
158 fn [<$ty _storage_hint_works>] () {
159 assert_eq!(
160 ::core::any::TypeId::of::<$ty>(),
161 ::core::any::TypeId::of::<<$ty as $crate::StorableHint<$crate::ManualKey<123>>>::Type>()
162 );
163 }
164 }
165 };
166 }
167 mod arrays {
168 use crate::storage_hint_works_for_primitive;
169
170 type Array = [i32; 4];
171 storage_hint_works_for_primitive!(Array);
172
173 type ArrayTuples = [(i32, i32); 2];
174 storage_hint_works_for_primitive!(ArrayTuples);
175 }
176
177 mod prims {
178 use crate::storage_hint_works_for_primitive;
179 use ink_primitives::AccountId;
180
181 storage_hint_works_for_primitive!(bool);
182 storage_hint_works_for_primitive!(String);
183 storage_hint_works_for_primitive!(AccountId);
184 storage_hint_works_for_primitive!(i8);
185 storage_hint_works_for_primitive!(i16);
186 storage_hint_works_for_primitive!(i32);
187 storage_hint_works_for_primitive!(i64);
188 storage_hint_works_for_primitive!(i128);
189 storage_hint_works_for_primitive!(u8);
190 storage_hint_works_for_primitive!(u16);
191 storage_hint_works_for_primitive!(u32);
192 storage_hint_works_for_primitive!(u64);
193 storage_hint_works_for_primitive!(u128);
194
195 type OptionU8 = Option<u8>;
196 storage_hint_works_for_primitive!(OptionU8);
197
198 type ResultU8 = Result<u8, bool>;
199 storage_hint_works_for_primitive!(ResultU8);
200
201 type BoxU8 = Box<u8>;
202 storage_hint_works_for_primitive!(BoxU8);
203
204 type BoxOptionU8 = Box<Option<u8>>;
205 storage_hint_works_for_primitive!(BoxOptionU8);
206 }
207
208 mod tuples {
209 use crate::storage_hint_works_for_primitive;
210
211 type TupleSix = (i32, u32, String, u8, bool, Box<Option<i32>>);
212 storage_hint_works_for_primitive!(TupleSix);
213 }
214
215 #[test]
216 fn storage_key_types_works() {
217 assert_eq!(<AutoKey as StorageKey>::KEY, 0);
218 assert_eq!(<ManualKey<123> as StorageKey>::KEY, 123);
219 assert_eq!(<ManualKey<0> as StorageKey>::KEY, 0);
220 assert_eq!(<ResolverKey<AutoKey, AutoKey> as StorageKey>::KEY, 0);
221 assert_eq!(
222 <ResolverKey<AutoKey, ManualKey<123>> as StorageKey>::KEY,
223 123
224 );
225 assert_eq!(
226 <ResolverKey<ManualKey<456>, ManualKey<123>> as StorageKey>::KEY,
227 456
228 );
229 assert_eq!(
230 <ResolverKey<ManualKey<0>, ManualKey<123>> as StorageKey>::KEY,
231 0
232 );
233 }
234}