subweight_core/parse/
storage.rs1use std::path::Path;
2use syn::{BinOp, Expr, ExprStruct, Item, ItemConst, Type};
3
4use crate::{parse::path_to_string, term::SimpleTerm as Term};
5
6#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7pub enum Db {
8 Parity,
9 Rocks,
10}
11
12#[derive(Debug, PartialEq, Eq, Clone)]
13pub struct RWs {
14 pub read: Term,
15 pub write: Term,
16}
17
18#[derive(Debug, PartialEq, Eq, Clone)]
19pub struct Weights {
20 pub db: Db,
21 pub weights: RWs,
22}
23
24#[macro_export]
26macro_rules! reads {
27 ($a:expr) => {
28 SimpleTerm::Mul($a.into(), SimpleTerm::Var($crate::scope::STORAGE_READ_VAR.into()).into())
29 };
30}
31
32#[macro_export]
34macro_rules! creads {
35 ($a:expr) => {
36 Term::Mul($a.into(), Term::Var($crate::scope::STORAGE_READ_VAR.into()).into())
37 };
38}
39
40#[macro_export]
42macro_rules! writes {
43 ($a:expr) => {
44 SimpleTerm::Mul($a.into(), SimpleTerm::Var($crate::scope::STORAGE_WRITE_VAR.into()).into())
45 };
46}
47
48#[macro_export]
50macro_rules! cwrites {
51 ($a:expr) => {
52 Term::Mul($a.into(), Term::Var($crate::scope::STORAGE_WRITE_VAR.into()).into())
53 };
54}
55
56pub fn parse_file(file: &Path) -> Result<Weights, String> {
60 let content = super::read_file(file)?;
61 parse_content(content)
62}
63
64pub fn parse_content(content: String) -> Result<Weights, String> {
65 let ast = syn::parse_file(&content).map_err(|e| e.to_string())?;
66 for item in ast.items {
67 if let Ok(res) = handle_item(&item) {
68 return Ok(res)
69 }
70 }
71 Err("No DB weights found".to_string())
72}
73
74fn handle_item(item: &Item) -> Result<Weights, String> {
75 match item {
76 Item::Mod(m) => {
78 if m.ident == "constants" {
79 if let Some((_, content)) = m.content.as_ref() {
80 for item in content {
81 let res = handle_item(item);
82 if res.is_ok() {
84 return res
85 }
86 }
87 return Err("Did not find parameter_types!".into())
88 }
89 }
90 Err(format!("Unexpected module: {}", m.ident))
91 },
92 Item::Macro(m) => {
93 let name = m.mac.path.segments.last();
94 if name.unwrap().ident == "parameter_types" {
95 parse_macro(m.mac.tokens.clone())
96 } else {
97 Err("Unexpected macro def".into())
98 }
99 },
100 _ => Err("Could not find DB weights in the file".into()),
101 }
102}
103
104fn parse_macro(tokens: proc_macro2::TokenStream) -> Result<Weights, String> {
114 let def: ItemConst = syn::parse2(tokens).map_err(|e| e.to_string())?;
115 let name = def.ident.to_string();
116
117 let db = match name.as_str() {
118 "RocksDbWeight" => Db::Rocks,
119 "ParityDbWeight" => Db::Parity,
120 _ => return Err(format!("Unexpected const name: {}", name)),
121 };
122 let type_name = type_to_string(&def.ty, None)?;
123 if type_name != "RuntimeDbWeight" {
124 return Err(format!("Unexpected const type: {}", type_name))
125 }
126 match def.expr.as_ref() {
127 Expr::Struct(s) => {
128 let weights = parse_runtime_db_weight(s)?;
129 Ok(Weights { db, weights })
130 },
131 _ => Err("Unexpected const value".into()),
132 }
133}
134
135fn parse_runtime_db_weight(expr: &ExprStruct) -> Result<RWs, String> {
136 let name = path_to_string(&expr.path, None);
137 if name != "RuntimeDbWeight" {
138 return Err(format!("Unexpected struct name: {}", name))
139 } else if expr.fields.len() != 2 {
140 return Err("Unexpected struct fields".into())
141 }
142 let reads = expr
143 .fields
144 .iter()
145 .find(|f| member_to_string(&f.member) == "read")
146 .ok_or("No read field found")?;
147 let writes = expr
148 .fields
149 .iter()
150 .find(|f| member_to_string(&f.member) == "write")
151 .ok_or("No write field found")?;
152
153 let read = parse_expression(&reads.expr)?;
154 let write = parse_expression(&writes.expr)?;
155
156 Ok(RWs { read, write })
157}
158
159fn parse_expression(expr: &Expr) -> Result<Term, String> {
160 match expr {
161 Expr::Binary(bin) => {
162 let left = parse_expression(&bin.left)?.into();
163 let right = parse_expression(&bin.right)?.into();
164
165 let term = match bin.op {
166 BinOp::Mul(_) => Term::Mul(left, right),
167 BinOp::Add(_) => Term::Add(left, right),
168 _ => return Err("Unexpected operator".into()),
169 };
170 Ok(term)
171 },
172 Expr::Lit(lit) => Ok(Term::Scalar(super::pallet::lit_to_value(&lit.lit))),
173 Expr::Path(p) => Ok(Term::Var(crate::term::VarValue(path_to_string(&p.path, Some("::"))))),
174 _ => Err("Unexpected expression storage expr".into()),
175 }
176}
177
178fn type_to_string(p: &syn::Type, delimiter: Option<&str>) -> Result<String, String> {
180 if let Type::Path(p) = p {
181 Ok(path_to_string(&p.path, delimiter))
182 } else {
183 Err("Unexpected type".into())
184 }
185}
186
187fn member_to_string(m: &syn::Member) -> String {
188 match m {
189 syn::Member::Named(ident) => ident.to_string(),
190 _ => "".into(),
191 }
192}