1234567891011121314151617181920#![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;2930313233#[proc_macro_derive(WeightDebug)]34pub fn derive_weight_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {35 derive_debug(input, format_weight)36}37383940#[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}848586#[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}