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
// This file is part of Substrate.

// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::pallet::Def;

/// * Add derive trait on Pallet
/// * Implement GetPalletVersion on Pallet
/// * Implement OnGenesis on Pallet
/// * Implement ModuleErrorMetadata on Pallet
/// * declare Module type alias for construct_runtime
/// * replace the first field type of `struct Pallet` with `PhantomData` if it is `_`
pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
	let frame_support = &def.frame_support;
	let frame_system = &def.frame_system;
	let type_impl_gen = &def.type_impl_generics(def.pallet_struct.attr_span);
	let type_use_gen = &def.type_use_generics(def.pallet_struct.attr_span);
	let type_decl_gen = &def.type_decl_generics(def.pallet_struct.attr_span);
	let pallet_ident = &def.pallet_struct.pallet;
	let config_where_clause = &def.config.where_clause;

	let pallet_item = {
		let pallet_module_items = &mut def.item.content.as_mut().expect("Checked by def").1;
		let item = &mut pallet_module_items[def.pallet_struct.index];
		if let syn::Item::Struct(item) = item {
			item
		} else {
			unreachable!("Checked by pallet struct parser")
		}
	};

	// If the first field type is `_` then we replace with `PhantomData`
	if let Some(field) = pallet_item.fields.iter_mut().next() {
		if field.ty == syn::parse_quote!(_) {
			field.ty = syn::parse_quote!(
				#frame_support::sp_std::marker::PhantomData<(#type_use_gen)>
			);
		}
	}

	pallet_item.attrs.push(syn::parse_quote!(
		#[derive(
			#frame_support::CloneNoBound,
			#frame_support::EqNoBound,
			#frame_support::PartialEqNoBound,
			#frame_support::RuntimeDebugNoBound,
		)]
	));

	let module_error_metadata = if let Some(error_def) = &def.error {
		let error_ident = &error_def.error;
		quote::quote_spanned!(def.pallet_struct.attr_span =>
			impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
				for #pallet_ident<#type_use_gen>
				#config_where_clause
			{
				fn metadata() -> &'static [#frame_support::error::ErrorMetadata] {
					<
						#error_ident<#type_use_gen> as #frame_support::error::ModuleErrorMetadata
					>::metadata()
				}
			}
		)
	} else {
		quote::quote_spanned!(def.pallet_struct.attr_span =>
			impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
				for #pallet_ident<#type_use_gen>
				#config_where_clause
			{
				fn metadata() -> &'static [#frame_support::error::ErrorMetadata] {
					&[]
				}
			}
		)
	};

	quote::quote_spanned!(def.pallet_struct.attr_span =>
		#module_error_metadata

		/// Type alias to `Pallet`, to be used by `construct_runtime`.
		///
		/// Generated by `pallet` attribute macro.
		pub type Module<#type_decl_gen> = #pallet_ident<#type_use_gen>;

		// Implement `GetPalletVersion` for `Pallet`
		impl<#type_impl_gen> #frame_support::traits::GetPalletVersion
			for #pallet_ident<#type_use_gen>
			#config_where_clause
		{
			fn current_version() -> #frame_support::traits::PalletVersion {
				#frame_support::crate_to_pallet_version!()
			}

			fn storage_version() -> Option<#frame_support::traits::PalletVersion> {
				let key = #frame_support::traits::PalletVersion::storage_key::<
						<T as #frame_system::Config>::PalletInfo, Self
					>().expect("Every active pallet has a name in the runtime; qed");

				#frame_support::storage::unhashed::get(&key)
			}
		}

		// Implement `OnGenesis` for `Pallet`
		impl<#type_impl_gen> #frame_support::traits::OnGenesis
			for #pallet_ident<#type_use_gen>
			#config_where_clause
		{
			fn on_genesis() {
				#frame_support::crate_to_pallet_version!()
					.put_into_storage::<<T as #frame_system::Config>::PalletInfo, Self>();
			}
		}
	)
}