use std::collections::HashSet;
use proc_macro2::Span;
use quote::ToTokens;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypegenError {
#[error("Could not parse into a syn type: {0}")]
SynParseError(#[from] syn::Error),
#[error("Fields should either be all named or all unnamed, make sure you are providing a valid metadata: {0}")]
InvalidFields(String),
#[error("A type in the metadata was invalid: {0}")]
InvalidType(String),
#[error("Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.")]
CompactPathNone,
#[error("Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.")]
DecodedBitsPathNone,
#[error("Could not find type with ID {0} in the type registry.")]
TypeNotFound(u32),
#[error("Type substitution error: {0}")]
InvalidSubstitute(#[from] TypeSubstitutionError),
#[error("Settings do not fit the given type registry: {0}")]
SettingsValidation(SettingsValidationError),
#[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),
}
#[derive(Debug, thiserror::Error)]
pub struct TypeSubstitutionError {
pub span: Span,
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))
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypeSubstitutionErrorKind {
#[error("`substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'")]
ExpectedAbsolutePath,
#[error("Substitute types must have a valid path.")]
EmptySubstitutePath,
#[error("Expected the from/to type generics to have the form 'Foo<A,B,C..>'.")]
ExpectedAngleBracketGenerics,
#[error("Expected an ident like 'Foo' or 'A' to mark a type to be substituted.")]
InvalidFromType,
#[error("Expected an ident like 'Foo' or an absolute concrete path like '::path::to::Bar' for the substitute type.")]
InvalidToType,
#[error("Cannot find matching param on 'from' type.")]
NoMatchingFromType,
}
#[derive(Debug, thiserror::Error, Default, PartialEq, Eq)]
pub struct SettingsValidationError {
pub derives_for_unknown_types: Vec<(syn::Path, HashSet<syn::Path>)>,
pub attributes_for_unknown_types: Vec<(syn::Path, HashSet<syn::Attribute>)>,
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()
}
}