ink_storage_traits/layout/
impls.rs

1// Copyright (C) Use Ink (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
15use crate::{
16    Packed,
17    StorageLayout,
18};
19use ink_metadata::layout::{
20    ArrayLayout,
21    Discriminant,
22    EnumLayout,
23    FieldLayout,
24    Layout,
25    LayoutKey,
26    LeafLayout,
27    StructLayout,
28};
29use ink_prelude::{
30    boxed::Box,
31    collections::{
32        BTreeMap,
33        BTreeSet,
34        VecDeque,
35    },
36    string::String,
37    vec::Vec,
38};
39use ink_primitives::{
40    AccountId,
41    Address,
42    Hash,
43    Key,
44    H160,
45    H256,
46    U256,
47};
48use scale_info::TypeInfo;
49
50macro_rules! impl_storage_layout_for_primitives {
51    ( $($name:ty),* $(,)? ) => {
52        $(
53            impl StorageLayout for $name {
54                fn layout(key: &Key) -> Layout {
55                    Layout::Leaf(LeafLayout::from_key::<$name>(LayoutKey::from(key)))
56                }
57            }
58        )*
59    };
60}
61#[rustfmt::skip]
62impl_storage_layout_for_primitives!(
63    AccountId, Address, Hash, String,
64    H160, H256, U256,
65    bool, char, (),
66    u8, u16, u32, u64, u128,
67    i8, i16, i32, i64, i128,
68);
69
70macro_rules! impl_layout_for_tuple {
71    ( $(($frag:ident, $id:literal)),* $(,)? ) => {
72        const _: () = {
73            // The name of the tuple looks like `(A)`, `(A, B)` ... `(A, B, ..., J)`
74            const TUPLE_NAME: &'static str = stringify!(($($frag),*));
75
76            impl<$($frag),*> StorageLayout for ($($frag),* ,)
77            where
78                $(
79                    $frag: StorageLayout,
80                )*
81            {
82                fn layout(key: &Key) -> Layout {
83                    Layout::Struct(
84                        StructLayout::new(
85                            TUPLE_NAME,
86                            [
87                                $(
88                                    FieldLayout::new(
89                                        ::core::stringify!($id),
90                                        <$frag as StorageLayout>::layout(key)
91                                    ),
92                                )*
93                            ]
94                        )
95                    )
96                }
97            }
98        };
99    }
100}
101
102impl_layout_for_tuple!((A, 0));
103impl_layout_for_tuple!((A, 0), (B, 1));
104impl_layout_for_tuple!((A, 0), (B, 1), (C, 2));
105impl_layout_for_tuple!((A, 0), (B, 1), (C, 2), (D, 3));
106impl_layout_for_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4));
107impl_layout_for_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
108impl_layout_for_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
109impl_layout_for_tuple!(
110    (A, 0),
111    (B, 1),
112    (C, 2),
113    (D, 3),
114    (E, 4),
115    (F, 5),
116    (G, 6),
117    (H, 7)
118);
119impl_layout_for_tuple!(
120    (A, 0),
121    (B, 1),
122    (C, 2),
123    (D, 3),
124    (E, 4),
125    (F, 5),
126    (G, 6),
127    (H, 7),
128    (I, 8)
129);
130impl_layout_for_tuple!(
131    (A, 0),
132    (B, 1),
133    (C, 2),
134    (D, 3),
135    (E, 4),
136    (F, 5),
137    (G, 6),
138    (H, 7),
139    (I, 8),
140    (J, 9)
141);
142
143impl<T, const N: usize> StorageLayout for [T; N]
144where
145    T: StorageLayout + Packed,
146{
147    fn layout(key: &Key) -> Layout {
148        let len: u32 = N as u32;
149        // Generic type is packed, so it doesn't take any cell
150        Layout::Array(ArrayLayout::new(
151            LayoutKey::from(key),
152            len,
153            <T as StorageLayout>::layout(key),
154        ))
155    }
156}
157
158impl<T> StorageLayout for Box<T>
159where
160    T: StorageLayout,
161{
162    fn layout(key: &Key) -> Layout {
163        <T as StorageLayout>::layout(key)
164    }
165}
166
167impl<T> StorageLayout for Option<T>
168where
169    T: StorageLayout,
170{
171    fn layout(key: &Key) -> Layout {
172        Layout::Enum(EnumLayout::new(
173            "Option",
174            key,
175            [
176                (Discriminant::from(0), StructLayout::new("None", Vec::new())),
177                (
178                    Discriminant::from(1),
179                    StructLayout::new(
180                        "Some",
181                        [FieldLayout::new("0", <T as StorageLayout>::layout(key))],
182                    ),
183                ),
184            ],
185        ))
186    }
187}
188
189impl<T, E> StorageLayout for Result<T, E>
190where
191    T: StorageLayout,
192    E: StorageLayout,
193{
194    fn layout(key: &Key) -> Layout {
195        Layout::Enum(EnumLayout::new(
196            "Result",
197            *key,
198            [
199                (
200                    Discriminant::from(0),
201                    StructLayout::new(
202                        "Ok",
203                        [FieldLayout::new("0", <T as StorageLayout>::layout(key))],
204                    ),
205                ),
206                (
207                    Discriminant::from(1),
208                    StructLayout::new(
209                        "Err",
210                        [FieldLayout::new("1", <E as StorageLayout>::layout(key))],
211                    ),
212                ),
213            ],
214        ))
215    }
216}
217
218impl<T> StorageLayout for Vec<T>
219where
220    T: TypeInfo + 'static + Packed,
221{
222    fn layout(key: &Key) -> Layout {
223        Layout::Leaf(LeafLayout::from_key::<Self>(LayoutKey::from(key)))
224    }
225}
226
227impl<K, V> StorageLayout for BTreeMap<K, V>
228where
229    K: TypeInfo + 'static + Packed,
230    V: TypeInfo + 'static + Packed,
231{
232    fn layout(key: &Key) -> Layout {
233        Layout::Leaf(LeafLayout::from_key::<Self>(LayoutKey::from(key)))
234    }
235}
236
237impl<T> StorageLayout for BTreeSet<T>
238where
239    T: TypeInfo + 'static + Packed,
240{
241    fn layout(key: &Key) -> Layout {
242        Layout::Leaf(LeafLayout::from_key::<Self>(LayoutKey::from(key)))
243    }
244}
245
246impl<T> StorageLayout for VecDeque<T>
247where
248    T: TypeInfo + 'static + Packed,
249{
250    fn layout(key: &Key) -> Layout {
251        Layout::Leaf(LeafLayout::from_key::<Self>(LayoutKey::from(key)))
252    }
253}