1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use std::collections::HashSet;

use proc_macro2::Span;
use quote::ToTokens;

/// Error for when something went wrong during type generation.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypegenError {
    /// Could not parse into a syn type.
    #[error("Could not parse into a syn type: {0}")]
    SynParseError(#[from] syn::Error),
    /// Fields should either be all named or all unnamed, make sure you are providing a valid metadata.
    #[error("Fields should either be all named or all unnamed, make sure you are providing a valid metadata: {0}")]
    InvalidFields(String),
    /// A type in the metadata was invalid
    #[error("A type in the metadata was invalid: {0}")]
    InvalidType(String),
    /// Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.
    #[error("Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.")]
    CompactPathNone,
    /// Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.
    #[error("Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.")]
    DecodedBitsPathNone,
    /// Could not find type with ID in the type registry.
    #[error("Could not find type with ID {0} in the type registry.")]
    TypeNotFound(u32),
    /// Type substitution error.
    #[error("Type substitution error: {0}")]
    InvalidSubstitute(#[from] TypeSubstitutionError),
    /// The settings do not fit the given type registry.
    #[error("Settings do not fit the given type registry: {0}")]
    SettingsValidation(SettingsValidationError),
    /// There are two types with the the same type path but a different structure.
    /// Use [`crate::utils::ensure_unique_type_paths`] on your [`scale_info::PortableRegistry`] to deduplicate type paths.
    #[error("There are two types with the the same type path {0} but different structure. Use `scale_typegen::utils::ensure_unique_type_paths` on your `PortableRegistry` before, to avoid this error.")]
    DuplicateTypePath(String),
}

/// Error attempting to do type substitution.
#[derive(Debug, thiserror::Error)]
pub struct TypeSubstitutionError {
    /// Where in the code the error occured.
    pub span: Span,
    /// Kind of TypeSubstitutionError that happended.
    pub kind: TypeSubstitutionErrorKind,
}

impl std::fmt::Display for TypeSubstitutionError {
    fn fmt(
        &self,
        f: &mut scale_info::prelude::fmt::Formatter<'_>,
    ) -> scale_info::prelude::fmt::Result {
        f.write_fmt(format_args!("{}", self.kind))
    }
}

/// Error attempting to do type substitution.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypeSubstitutionErrorKind {
    /// Substitute "to" type must be an absolute path.
    #[error("`substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'")]
    ExpectedAbsolutePath,
    /// Substitute types must have a valid path.
    #[error("Substitute types must have a valid path.")]
    EmptySubstitutePath,
    /// From/To substitution types should use angle bracket generics.
    #[error("Expected the from/to type generics to have the form 'Foo<A,B,C..>'.")]
    ExpectedAngleBracketGenerics,
    /// Source substitute type must be an ident.
    #[error("Expected an ident like 'Foo' or 'A' to mark a type to be substituted.")]
    InvalidFromType,
    /// Target type is invalid.
    #[error("Expected an ident like 'Foo' or an absolute concrete path like '::path::to::Bar' for the substitute type.")]
    InvalidToType,
    /// Target ident doesn't correspond to any source type.
    #[error("Cannot find matching param on 'from' type.")]
    NoMatchingFromType,
}

/// Error attempting to do type substitution.
#[derive(Debug, thiserror::Error, Default, PartialEq, Eq)]
pub struct SettingsValidationError {
    /// Cannot add derive for type that is not present in the registry.
    pub derives_for_unknown_types: Vec<(syn::Path, HashSet<syn::Path>)>,
    /// Cannot add attribute for type that is not present in the registry.
    pub attributes_for_unknown_types: Vec<(syn::Path, HashSet<syn::Attribute>)>,
    /// Invalid path to replace: the type getting substituted is not present in the registry.
    pub substitutes_for_unknown_types: Vec<(syn::Path, syn::Path)>,
}

impl std::fmt::Display for SettingsValidationError {
    fn fmt(
        &self,
        f: &mut scale_info::prelude::fmt::Formatter<'_>,
    ) -> scale_info::prelude::fmt::Result {
        fn display_one(e: &impl ToTokens) -> String {
            e.to_token_stream().to_string().replace(' ', "")
        }

        fn display_many(set: &HashSet<impl ToTokens>) -> String {
            set.iter()
                .map(|e| display_one(e))
                .collect::<Vec<_>>()
                .join(", ")
        }

        writeln!(f, "Settings validation error:")?;

        if !self.derives_for_unknown_types.is_empty() {
            writeln!(f, "  Derives for unknown types:")?;
            for (path, derives) in &self.derives_for_unknown_types {
                writeln!(
                    f,
                    "    {} (Derives: {})",
                    display_one(path),
                    display_many(derives)
                )?;
            }
        }

        if !self.attributes_for_unknown_types.is_empty() {
            writeln!(f, "  Attributes for unknown types:")?;
            for (path, attributes) in &self.attributes_for_unknown_types {
                writeln!(
                    f,
                    "    {} (Attributes: {})",
                    display_one(path),
                    display_many(attributes)
                )?;
            }
        }

        if !self.substitutes_for_unknown_types.is_empty() {
            writeln!(f, "  Substitutes for unknown types:")?;
            for (original, substitute) in &self.substitutes_for_unknown_types {
                writeln!(
                    f,
                    "    {} (Substitute: {})",
                    display_one(original),
                    display_one(substitute),
                )?;
            }
        }

        Ok(())
    }
}

impl SettingsValidationError {
    pub(crate) fn is_empty(&self) -> bool {
        self.derives_for_unknown_types.is_empty()
            && self.attributes_for_unknown_types.is_empty()
            && self.substitutes_for_unknown_types.is_empty()
    }
}