git.delta.rocks / unique-network / refs/commits / e8fdadb89923

difftreelog

source

pallets/contracts/proc-macro/src/lib.rs3.9 KiBsourcehistory
1// This file is part of Substrate.23// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.1718//! Proc macros used in the contracts module.1920#![no_std]2122extern crate alloc;2324use proc_macro2::TokenStream;25use quote::{quote, quote_spanned};26use syn::spanned::Spanned;27use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident};28use alloc::string::ToString;2930/// This derives `Debug` for a struct where each field must be of some numeric type.31/// It interprets each field as its represents some weight and formats it as times so that32/// it is readable by humans.33#[proc_macro_derive(WeightDebug)]34pub fn derive_weight_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {35	derive_debug(input, format_weight)36}3738/// This is basically identical to the std libs Debug derive but without adding any39/// bounds to existing generics.40#[proc_macro_derive(ScheduleDebug)]41pub fn derive_schedule_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {42	derive_debug(input, format_default)43}4445fn derive_debug(46	input: proc_macro::TokenStream,47	fmt: impl Fn(&Ident) -> TokenStream48) -> proc_macro::TokenStream {49	let input = parse_macro_input!(input as DeriveInput);50	let name = &input.ident;51	let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();52	let data = if let Data::Struct(data) = &input.data {53		data54	} else {55		return quote_spanned! {56			name.span() =>57			compile_error!("WeightDebug is only supported for structs.");58		}.into();59	};6061	#[cfg(feature = "full")]62	let fields = iterate_fields(data, fmt);6364	#[cfg(not(feature = "full"))]65	let fields = {66		drop(fmt);67		drop(data);68		TokenStream::new()69	};7071	let tokens = quote! {72		impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause {73			fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {74				use ::sp_runtime::{FixedPointNumber, FixedU128 as Fixed};75				let mut formatter = formatter.debug_struct(stringify!(#name));76				#fields77				formatter.finish()78			}79		}80	};8182	tokens.into()83}8485/// This is only used then the `full` feature is activated.86#[cfg(feature = "full")]87fn iterate_fields(data: &DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream {88	match &data.fields {89		Fields::Named(fields) => {90			let recurse = fields.named91			.iter()92			.filter_map(|f| {93				let name = f.ident.as_ref()?;94				if name.to_string().starts_with('_') {95					return None;96				}97				let value = fmt(name);98				let ret = quote_spanned!{ f.span() =>99					formatter.field(stringify!(#name), #value);100				};101				Some(ret)102			});103			quote!{104				#( #recurse )*105			}106		}107		Fields::Unnamed(fields) => quote_spanned!{108			fields.span() =>109			compile_error!("Unnamed fields are not supported")110		},111		Fields::Unit => quote!(),112	}113}114115fn format_weight(field: &Ident) -> TokenStream {116	quote_spanned! { field.span() =>117		&if self.#field > 1_000_000_000 {118			format!(119				"{:.1?} ms",120				Fixed::saturating_from_rational(self.#field, 1_000_000_000).to_float()121			)122		} else if self.#field > 1_000_000 {123			format!(124				"{:.1?} µs",125				Fixed::saturating_from_rational(self.#field, 1_000_000).to_float()126			)127		} else if self.#field > 1_000 {128			format!(129				"{:.1?} ns",130				Fixed::saturating_from_rational(self.#field, 1_000).to_float()131			)132		} else {133			format!("{} ps", self.#field)134		}135	}136}137138fn format_default(field: &Ident) -> TokenStream {139	quote_spanned! { field.span() =>140		&self.#field141	}142}