subweight_core/parse/
overhead.rs

1use syn::ItemConst;
2
3use crate::{
4	parse::path_to_string,
5	term::{ChromaticTerm, SimpleTerm},
6	*,
7};
8
9#[derive(Debug, PartialEq, Eq, Clone)]
10pub enum Weight {
11	BlockExecution(ChromaticTerm),
12	ExtrinsicBase(ChromaticTerm),
13}
14
15pub fn parse_file(file: &Path) -> Result<Weight, String> {
16	let content = super::read_file(file)?;
17	parse_content(content)
18}
19
20pub fn parse_content(content: String) -> Result<Weight, String> {
21	let ast = syn::parse_file(&content).map_err(|e| e.to_string())?;
22	for item in ast.items {
23		if let Ok(res) = handle_item(&item) {
24			return Ok(res)
25		}
26	}
27	Err("No Overhead weights found".to_string())
28}
29
30fn handle_item(item: &Item) -> Result<Weight, String> {
31	match item {
32		// The current Substrate template has a useless `constants` mod.
33		Item::Mod(m) => {
34			if m.ident == "constants" {
35				if let Some((_, content)) = m.content.as_ref() {
36					for item in content {
37						let res = handle_item(item);
38						// Ignore errors
39						if res.is_ok() {
40							return res
41						}
42					}
43					return Err("Did not find parameter_types!".into())
44				}
45			}
46			Err(format!("Unexpected module: {}", m.ident))
47		},
48		Item::Macro(m) => {
49			let name = m.mac.path.segments.last();
50			if name.unwrap().ident == "parameter_types" {
51				parse_macro(m.mac.tokens.clone())
52			} else {
53				Err("Unexpected macro def".into())
54			}
55		},
56		_ => Err("Could not find overhead weight in the file".into()),
57	}
58}
59
60/// Handles the content of the `parameter_types!` macro.
61///
62/// Example:
63/// ```nocompile
64/// pub const BlockExecutionWeight: Weight = 5_481_991 * WEIGHT_PER_NANOS;
65/// ```
66fn parse_macro(tokens: proc_macro2::TokenStream) -> Result<Weight, String> {
67	let def: ItemConst = syn::parse2(tokens).map_err(|e| e.to_string())?;
68	let name = def.ident.to_string();
69
70	let type_name = type_to_string(&def.ty, None)?;
71	if type_name != "Weight" {
72		return Err(format!("Unexpected const type: {}", type_name))
73	}
74	let weight: ChromaticTerm = match def.expr.as_ref() {
75		Expr::Binary(bin) => {
76			let simple: SimpleTerm = bin.try_into()?;
77			Ok(simple.into_chromatic(crate::Dimension::Time))
78		},
79		e => super::pallet::parse_expression(e),
80	}?;
81
82	match name.as_str() {
83		"BlockExecutionWeight" => Ok(Weight::BlockExecution(weight)),
84		"ExtrinsicBaseWeight" => Ok(Weight::ExtrinsicBase(weight)),
85		_ => Err(format!("Unexpected const name: {}", name)),
86	}
87}
88
89/// Expects a path to a type and returns the type name.
90fn type_to_string(p: &syn::Type, delimiter: Option<&str>) -> Result<String, String> {
91	if let Type::Path(p) = p {
92		Ok(path_to_string(&p.path, delimiter))
93	} else {
94		Err("Unexpected type".into())
95	}
96}