precompile_utils_macro/
precompile_name_from_address.rs1use super::*;
20use syn::{GenericArgument, Type};
21
22pub fn main(_: TokenStream, input: TokenStream) -> TokenStream {
23 let item = parse_macro_input!(input as ItemType);
24
25 let ItemType {
26 attrs,
27 vis,
28 type_token,
29 ident,
30 generics,
31 eq_token,
32 ty,
33 semi_token,
34 } = item;
35
36 if let Type::Tuple(ref type_tuple) = *ty {
37 let variants: Vec<(Ident, u64)> = type_tuple
38 .elems
39 .iter()
40 .filter_map(extract_precompile_name_and_prefix)
41 .collect();
42
43 let ident_expressions: Vec<&Ident> = variants.iter().map(|(ident, _)| ident).collect();
44 let variant_expressions: Vec<&u64> = variants.iter().map(|(_, id)| id).collect();
45
46 (quote! {
47 #(#attrs)*
48 #vis #type_token #ident #generics #eq_token #ty #semi_token
49
50 #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive, Debug)]
51 #[repr(u64)]
52 pub enum PrecompileName {
53 #(
54 #ident_expressions = #variant_expressions,
55 )*
56 }
57
58 impl PrecompileName {
59 pub fn from_address(address: sp_core::H160) -> Option<Self> {
60 let _u64 = address.to_low_u64_be();
61 if address == sp_core::H160::from_low_u64_be(_u64) {
62 use num_enum::TryFromPrimitive;
63 Self::try_from_primitive(_u64).ok()
64 } else {
65 None
66 }
67 }
68 }
69 })
70 .into()
71 } else {
72 quote_spanned! {
73 ty.span() => compile_error!("Expected tuple");
74 }
75 .into()
76 }
77}
78
79fn extract_precompile_name_and_prefix(type_: &Type) -> Option<(Ident, u64)> {
80 match type_ {
81 Type::Path(type_path) => {
82 if let Some(path_segment) = type_path.path.segments.last() {
83 match path_segment.ident.to_string().as_ref() {
84 "PrecompileAt" => {
85 extract_precompile_name_and_prefix_for_precompile_at(path_segment)
86 }
87 _ => None,
88 }
89 } else {
90 None
91 }
92 }
93 _ => None,
94 }
95}
96
97fn extract_precompile_name_and_prefix_for_precompile_at(
98 path_segment: &syn::PathSegment,
99) -> Option<(Ident, u64)> {
100 if let syn::PathArguments::AngleBracketed(generics) = &path_segment.arguments {
101 let mut iter = generics.args.iter();
102 if let (
103 Some(GenericArgument::Type(Type::Path(type_path_1))),
104 Some(GenericArgument::Type(Type::Path(type_path_2))),
105 ) = (iter.next(), iter.next())
106 {
107 if let (Some(path_segment_1), Some(path_segment_2)) = (
108 type_path_1.path.segments.last(),
109 type_path_2.path.segments.last(),
110 ) {
111 if let syn::PathArguments::AngleBracketed(generics_) = &path_segment_1.arguments {
112 if let Some(GenericArgument::Const(Expr::Lit(lit))) = generics_.args.first() {
113 if let Lit::Int(int) = &lit.lit {
114 if let Ok(precompile_id) = int.base10_parse() {
115 if &path_segment_2.ident.to_string() == "CollectivePrecompile" {
116 if let Some(instance_ident) =
117 precompile_instance_ident(path_segment_2)
118 {
119 return Some((instance_ident, precompile_id));
120 }
121 } else {
122 return Some((path_segment_2.ident.clone(), precompile_id));
123 }
124 }
125 }
126 }
127 }
128 }
129 }
130 }
131
132 None
133}
134
135fn precompile_instance_ident(path_segment: &syn::PathSegment) -> Option<Ident> {
136 if let syn::PathArguments::AngleBracketed(generics_) = &path_segment.arguments {
137 if let Some(GenericArgument::Type(Type::Path(instance_type_path))) = generics_.args.last() {
138 if let Some(instance_type) = instance_type_path.path.segments.last() {
139 return Some(instance_type.ident.clone());
140 }
141 }
142 }
143
144 None
145}