ink_macro/storage/
storable_hint.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 ink_ir::utils::find_storage_key_salt;
16use proc_macro2::TokenStream as TokenStream2;
17use quote::{
18    format_ident,
19    quote,
20    ToTokens,
21};
22use syn::{
23    parse2,
24    GenericParam,
25};
26
27fn storable_hint_inner(s: synstructure::Structure) -> TokenStream2 {
28    let ident = s.ast().ident.clone();
29    let salt_ident = format_ident!("__ink_generic_salt");
30
31    let mut generics = s.ast().generics.clone();
32    generics.params.push(
33        parse2(quote! { #salt_ident : ::ink::storage::traits::StorageKey }).unwrap(),
34    );
35
36    let (impl_generics, _, where_clause) = generics.split_for_impl();
37    let (_, ty_generics_original, _) = s.ast().generics.split_for_impl();
38
39    if let Some(inner_salt_ident) = find_storage_key_salt(s.ast()) {
40        let inner_salt_ident = inner_salt_ident.ident.to_token_stream();
41        let ty_generics: Vec<_> = s
42            .ast()
43            .generics
44            .params
45            .clone()
46            .into_iter()
47            .map(|param| {
48                let ident = match param {
49                    GenericParam::Type(t) => t.ident.to_token_stream(),
50                    GenericParam::Lifetime(l) => l.lifetime.to_token_stream(),
51                    GenericParam::Const(c) => c.ident.to_token_stream(),
52                };
53                if inner_salt_ident.to_string() == ident.to_string() {
54                    Some(quote! {
55                        #salt_ident
56                    })
57                } else {
58                    Some(ident)
59                }
60            })
61            .collect();
62
63        quote! {
64            impl #impl_generics ::ink::storage::traits::StorableHint<#salt_ident> for #ident #ty_generics_original #where_clause {
65                type Type = #ident <#(#ty_generics),*>;
66                type PreferredKey = #inner_salt_ident;
67            }
68        }
69    } else {
70        quote! {
71            impl #impl_generics ::ink::storage::traits::StorableHint<#salt_ident> for #ident #ty_generics_original #where_clause {
72                type Type = #ident #ty_generics_original;
73                type PreferredKey = ::ink::storage::traits::AutoKey;
74            }
75        }
76    }
77}
78
79pub fn storable_hint_derive(s: synstructure::Structure) -> TokenStream2 {
80    let derive = storable_hint_inner(s);
81
82    quote! {
83        const _ : () = {
84            #derive
85        };
86    }
87}