Skip to content

Commit

Permalink
Alias to RuntimeEvent rather than making another, and prep for substi…
Browse files Browse the repository at this point in the history
…tuting call type
  • Loading branch information
jsdw committed Mar 17, 2023
1 parent 756cad2 commit c377ff7
Show file tree
Hide file tree
Showing 4 changed files with 576 additions and 618 deletions.
87 changes: 41 additions & 46 deletions codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ use syn::parse_quote;
/// Error returned when the Codegen cannot generate the runtime API.
#[derive(Debug, thiserror::Error)]
pub enum CodegenError {
/// The given metadata type could not be found.
#[error("Could not find type with ID {0} in the type registry; please raise a support issue.")]
TypeNotFound(u32),
/// Cannot fetch the metadata bytes.
#[error("Failed to fetch metadata, make sure that you're pointing at a node which is providing V14 metadata: {0}")]
Fetch(#[from] FetchMetadataError),
Expand Down Expand Up @@ -80,12 +83,6 @@ pub enum CodegenError {
/// Metadata for storage could not be found.
#[error("Metadata for storage entry {0}_{1} could not be found. Make sure you are providing a valid metadata V14")]
MissingStorageMetadata(String, String),
/// StorageNMap should have N hashers.
#[error("Number of hashers ({0}) does not equal 1 for StorageMap, or match number of fields ({1}) for StorageNMap. Make sure you are providing a valid metadata V14")]
MismatchHashers(usize, usize),
/// Expected to find one hasher for StorageMap.
#[error("No hasher found for single key. Make sure you are providing a valid metadata V14")]
MissingHasher,
/// Metadata for call could not be found.
#[error("Metadata for call entry {0}_{1} could not be found. Make sure you are providing a valid metadata V14")]
MissingCallMetadata(String, String),
Expand Down Expand Up @@ -250,7 +247,23 @@ impl RuntimeGenerator {
) -> Result<TokenStream2, CodegenError> {
let item_mod_attrs = item_mod.attrs.clone();
let item_mod_ir = ir::ItemMod::try_from(item_mod)?;
let default_derives = derives.default_derives();

// Get the path to the `Runtime` struct. We assume that the same path contains
// RuntimeCall and RuntimeEvent.
let runtime_type_id = self.metadata.ty.id();
let runtime_path_segments = self
.metadata
.types
.resolve(runtime_type_id)
.ok_or(CodegenError::TypeNotFound(runtime_type_id))?
.path()
.namespace()
.iter()
.map(|part| syn::PathSegment::from(format_ident!("{}", part)));
let runtime_path = syn::Path {
leading_colon: None,
segments: syn::punctuated::Punctuated::from_iter(runtime_path_segments),
};

let type_gen = TypeGenerator::new(
&self.metadata.types,
Expand Down Expand Up @@ -338,53 +351,23 @@ impl RuntimeGenerator {
})
.collect::<Result<Vec<_>, CodegenError>>()?;

let outer_event_variants_and_match_arms = self.metadata.pallets.iter().filter_map(|p| {
let root_event_if_arms = self.metadata.pallets.iter().filter_map(|p| {
let variant_name_str = &p.name;
let variant_name = format_ident!("{}", variant_name_str);
let mod_name = format_ident!("{}", variant_name_str.to_string().to_snake_case());
let index = proc_macro2::Literal::u8_unsuffixed(p.index);

p.event.as_ref().map(|_| {
// The variant name to go into the event enum:
let outer_event_variant = quote! {
#[codec(index = #index)]
#variant_name(#mod_name::Event),
};

// An 'if' arm for the RootEvent impl to match this variant name:
let outer_event_match_arm = quote! {
quote! {
if pallet_name == #variant_name_str {
return Ok(Event::#variant_name(#mod_name::Event::decode_with_metadata(
&mut &*pallet_bytes,
pallet_ty,
metadata
)?));
}
};

(outer_event_variant, outer_event_match_arm)
})
}).collect::<Vec<_>>();

let outer_event_variants =
outer_event_variants_and_match_arms.iter().map(|v| &v.0);
let outer_event_match_arms =
outer_event_variants_and_match_arms.iter().map(|v| &v.1);

let outer_event = quote! {
#default_derives
pub enum Event {
#( #outer_event_variants )*
}

impl #crate_path::events::RootEvent for Event {
fn root_event(pallet_bytes: &[u8], pallet_name: &str, pallet_ty: u32, metadata: &#crate_path::Metadata) -> Result<Self, #crate_path::Error> {
use #crate_path::metadata::DecodeWithMetadata;
#( #outer_event_match_arms )*
Err(#crate_path::ext::scale_decode::Error::custom(format!("Pallet name '{}' not found in root Event enum", pallet_name)).into())
}
}
};
})
});

let mod_ident = &item_mod_ir.ident;
let pallets_with_constants: Vec<_> = pallets_with_mod_names
Expand Down Expand Up @@ -423,14 +406,23 @@ impl RuntimeGenerator {
// Identify the pallets composing the static metadata by name.
pub static PALLETS: [&str; #pallet_names_len] = [ #(#pallet_names,)* ];

#outer_event
#( #modules )*
#types_mod
/// The statically generated runtime call type.
pub type Call = #types_mod_ident::#runtime_path::RuntimeCall;

/// The default error type returned when there is a runtime issue,
/// exposed here for ease of use.
/// The error type returned when there is a runtime issue.
pub type DispatchError = #types_mod_ident::sp_runtime::DispatchError;

// Make the runtime event type easily accessible, and impl RootEvent to help decode into it.
pub type Event = #types_mod_ident::#runtime_path::RuntimeEvent;

impl #crate_path::events::RootEvent for Event {
fn root_event(pallet_bytes: &[u8], pallet_name: &str, pallet_ty: u32, metadata: &#crate_path::Metadata) -> Result<Self, #crate_path::Error> {
use #crate_path::metadata::DecodeWithMetadata;
#( #root_event_if_arms )*
Err(#crate_path::ext::scale_decode::Error::custom(format!("Pallet name '{}' not found in root Event enum", pallet_name)).into())
}
}

pub fn constants() -> ConstantsApi {
ConstantsApi
}
Expand Down Expand Up @@ -479,6 +471,9 @@ impl RuntimeGenerator {
Ok(())
}
}

#( #modules )*
#types_mod
}
})
}
Expand Down
5 changes: 4 additions & 1 deletion codegen/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ pub use self::{
Derives,
DerivesRegistry,
},
substitutes::TypeSubstitutes,
substitutes::{
AbsolutePath,
TypeSubstitutes,
},
type_def::TypeDefGen,
type_def_params::TypeDefParameters,
type_path::{
Expand Down
97 changes: 63 additions & 34 deletions codegen/src/types/substitutes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,48 +108,77 @@ impl TypeSubstitutes {
}
}

/// Only insert the given substitution if a substitution at that path doesn't
/// already exist.
pub fn insert_if_not_exists(
&mut self,
source: syn::Path,
target: AbsolutePath,
) -> Result<(), CodegenError> {
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
self.substitutes.entry(key).or_insert(val);
Ok(())
}

/// Add a bunch of source to target type substitutions.
pub fn extend(
&mut self,
elems: impl IntoIterator<Item = (syn::Path, AbsolutePath)>,
) -> Result<(), CodegenError> {
let to_extend = elems.into_iter().map(|(path, AbsolutePath(mut with))| {
let Some(syn::PathSegment { arguments: src_path_args, ..}) = path.segments.last() else {
return Err(CodegenError::EmptySubstitutePath(path.span()))
};
let Some(syn::PathSegment { arguments: target_path_args, ..}) = with.segments.last_mut() else {
return Err(CodegenError::EmptySubstitutePath(with.span()))
};
for (source, target) in elems.into_iter() {
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
self.substitutes.insert(key, val);
}
Ok(())
}

let source_args: Vec<_> = type_args(src_path_args).collect();
/// Given a source and target path, parse the type params to work out the mapping from
/// source to target, and output the source => substitution mapping that we work out from this.
fn parse_path_substitution(
src_path: syn::Path,
mut target_path: syn::Path,
) -> Result<(PathSegments, Substitute), CodegenError> {
let Some(syn::PathSegment { arguments: src_path_args, ..}) = src_path.segments.last() else {
return Err(CodegenError::EmptySubstitutePath(src_path.span()))
};
let Some(syn::PathSegment { arguments: target_path_args, ..}) = target_path.segments.last_mut() else {
return Err(CodegenError::EmptySubstitutePath(target_path.span()))
};

let param_mapping = if source_args.is_empty() {
// If the type parameters on the source type are not specified, then this means that
// the type is either not generic or the user wants to pass through all the parameters
TypeParamMapping::None
} else {
// Describe the mapping in terms of "which source param idx is used for each target param".
// So, for each target param, find the matching source param index.
let mapping = type_args(target_path_args)
.filter_map(|arg|
source_args
.iter()
.position(|&src| src == arg)
.map(|src_idx|
u8::try_from(src_idx).expect("type arguments to be fewer than 256; qed"),
)
).collect();
TypeParamMapping::Specified(mapping)
};
let source_args: Vec<_> = type_args(src_path_args).collect();

// NOTE: Params are late bound and held separately, so clear them
// here to not mess pretty printing this path and params together
*target_path_args = syn::PathArguments::None;
let param_mapping = if source_args.is_empty() {
// If the type parameters on the source type are not specified, then this means that
// the type is either not generic or the user wants to pass through all the parameters
TypeParamMapping::None
} else {
// Describe the mapping in terms of "which source param idx is used for each target param".
// So, for each target param, find the matching source param index.
let mapping = type_args(target_path_args)
.filter_map(|arg| {
source_args
.iter()
.position(|&src| src == arg)
.map(|src_idx| {
u8::try_from(src_idx)
.expect("type arguments to be fewer than 256; qed")
})
})
.collect();
TypeParamMapping::Specified(mapping)
};

Ok((PathSegments::from(&path), Substitute { path: with, param_mapping }))
}).collect::<Result<Vec<_>, _>>()?;
// Now that we've parsed the type params from our target path, remove said params from
// that path, since we're storing them separately.
*target_path_args = syn::PathArguments::None;

self.substitutes.extend(to_extend);
Ok(())
Ok((
PathSegments::from(&src_path),
Substitute {
path: target_path,
param_mapping,
},
))
}

/// Given a source type path, return a substituted type path if a substitution is defined.
Expand Down Expand Up @@ -249,7 +278,7 @@ fn is_absolute(path: &syn::Path) -> bool {
.map_or(false, |segment| segment.ident == "crate")
}

pub struct AbsolutePath(syn::Path);
pub struct AbsolutePath(pub syn::Path);

impl TryFrom<syn::Path> for AbsolutePath {
type Error = (syn::Path, String);
Expand Down
Loading

0 comments on commit c377ff7

Please sign in to comment.