scale_typegen/typegen/
validation.rs1use scale_info::{form::PortableForm, PortableRegistry};
2use syn::parse_quote;
3
4use crate::{DerivesRegistry, TypeSubstitutes};
5
6use super::{
7 error::SettingsValidationError,
8 settings::substitutes::{path_segments, PathSegments, TryIntoSynPath},
9};
10
11pub fn validate_substitutes_and_derives_against_registry(
17 substitutes: &TypeSubstitutes,
18 derives: &DerivesRegistry,
19 types: &PortableRegistry,
20) -> Result<(), SettingsValidationError> {
21 let mut error = SettingsValidationError::default();
22
23 for (path, derives_and_attrs) in derives.derives_on_specific_types() {
24 let path_segments = path_segments(&path.path);
25 if !registry_contains_type_path(types, &path_segments) {
26 let attributes = derives_and_attrs.attributes();
27 let derives = derives_and_attrs.derives();
28
29 if !attributes.is_empty() {
30 let already_in_err = error
31 .attributes_for_unknown_types
32 .iter_mut()
33 .find(|(e, _)| e == &path.path);
34
35 match already_in_err {
36 Some(e) => e.1.extend(attributes.iter().cloned()),
37 None => error
38 .attributes_for_unknown_types
39 .push((path.path.clone(), attributes.clone())),
40 }
41 }
42
43 if !derives.is_empty() {
44 let already_in_err = error
45 .derives_for_unknown_types
46 .iter_mut()
47 .find(|(e, _)| e == &path.path);
48
49 match already_in_err {
50 Some(e) => e.1.extend(derives.iter().cloned()),
51 None => error
52 .derives_for_unknown_types
53 .push((path.path.clone(), derives.clone())),
54 }
55 }
56 }
57 }
58
59 for (path, sub) in substitutes.iter() {
60 if !registry_contains_type_path(types, path) {
61 error
62 .substitutes_for_unknown_types
63 .push((path_segments_to_syn_path(path), sub.path().clone()))
64 }
65 }
66
67 if error.is_empty() {
68 Ok(())
69 } else {
70 Err(error)
71 }
72}
73
74fn path_segments_to_syn_path(segments: &PathSegments) -> syn::Path {
80 if segments.is_empty() {
81 panic!("Path in Substitutes should not be empty.")
82 }
83 let segments = segments.iter().map(|e| {
84 syn::parse_str::<syn::PathSegment>(e)
85 .expect("PathSegments should be syn::PathSegment compatible")
86 });
87 parse_quote!(#(#segments)::*)
88}
89
90pub fn registry_contains_type_path(types: &PortableRegistry, path: &[String]) -> bool {
92 types.types.iter().any(|t| t.ty.path.segments == *path)
93}
94
95pub fn similar_type_paths_in_registry(
97 types: &PortableRegistry,
98 path: &syn::Path,
99) -> Vec<syn::Path> {
100 let scale_type_path = scale_info::Path::<PortableForm> {
101 segments: path.segments.iter().map(|e| e.ident.to_string()).collect(),
102 };
103 if scale_type_path.ident().is_none() {
104 return vec![];
105 }
106
107 types
109 .types
110 .iter()
111 .filter_map(|t| {
112 let path = &t.ty.path;
113 path.ident()
114 .filter(|ident| ident == scale_type_path.ident().as_ref().expect("qed"))?;
115 path.syn_path()
116 })
117 .collect()
118}