Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

[WIP]: Construct Runtime v2 #14788

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'master' of github.com:paritytech/substrate into gupnik/…
…cr-v2
gupnik committed Jul 30, 2023
commit 063ab98d3e29521ca89bd9b30b465d65675f93cb
117 changes: 113 additions & 4 deletions frame/support/procedural/src/lib.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@
mod benchmark;
mod clone_no_bound;
mod construct_runtime;
mod construct_runtime_v2;
mod crate_version;
mod debug_no_bound;
mod default_no_bound;
@@ -417,6 +416,11 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream {
construct_runtime::construct_runtime(input)
}

#[proc_macro_attribute]
pub fn construct_runtime_v2(attr: TokenStream, item: TokenStream) -> TokenStream {
construct_runtime_v2::construct_runtime(attr, item)
}

/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify
/// pallet information.
///
@@ -1764,7 +1768,112 @@ pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream {
pallet_macro_stub()
}

/// Can be attached to a module. Doing so will declare that module as importable into a pallet
/// via [`#[import_section]`](`macro@import_section`).
///
/// Note that sections are imported by their module name/ident, and should be referred to by
/// their _full path_ from the perspective of the target pallet. Do not attempt to make use
/// of `use` statements to bring pallet sections into scope, as this will not work (unless
/// you do so as part of a wildcard import, in which case it will work).
///
/// ## Naming Logistics
///
/// Also note that because of how `#[pallet_section]` works, pallet section names must be
/// globally unique _within the crate in which they are defined_. For more information on
/// why this must be the case, see macro_magic's
/// [`#[export_tokens]`](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) macro.
///
/// Optionally, you may provide an argument to `#[pallet_section]` such as
/// `#[pallet_section(some_ident)]`, in the event that there is another pallet section in
/// same crate with the same ident/name. The ident you specify can then be used instead of
/// the module's ident name when you go to import it via `#[import_section]`.
#[proc_macro_attribute]
pub fn construct_runtime_v2(attr: TokenStream, item: TokenStream) -> TokenStream {
construct_runtime_v2::construct_runtime(attr, item)
}
pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream {
let tokens_clone = tokens.clone();
// ensure this can only be attached to a module
let _mod = parse_macro_input!(tokens_clone as ItemMod);

// use macro_magic's export_tokens as the internal implementation otherwise
match macro_magic::mm_core::export_tokens_internal(attr, tokens, false) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}

/// An attribute macro that can be attached to a module declaration. Doing so will
/// Imports the contents of the specified external pallet section that was defined
/// previously using [`#[pallet_section]`](`macro@pallet_section`).
///
/// ## Example
/// ```ignore
/// #[import_section(some_section)]
/// #[pallet]
/// pub mod pallet {
/// // ...
/// }
/// ```
/// where `some_section` was defined elsewhere via:
/// ```ignore
/// #[pallet_section]
/// pub mod some_section {
/// // ...
/// }
/// ```
///
/// This will result in the contents of `some_section` being _verbatim_ imported into
/// the pallet above. Note that since the tokens for `some_section` are essentially
/// copy-pasted into the target pallet, you cannot refer to imports that don't also
/// exist in the target pallet, but this is easily resolved by including all relevant
/// `use` statements within your pallet section, so they are imported as well, or by
/// otherwise ensuring that you have the same imports on the target pallet.
///
/// It is perfectly permissible to import multiple pallet sections into the same pallet,
/// which can be done by having multiple `#[import_section(something)]` attributes
/// attached to the pallet.
///
/// Note that sections are imported by their module name/ident, and should be referred to by
/// their _full path_ from the perspective of the target pallet.
#[import_tokens_attr {
format!(
"{}::macro_magic",
match generate_crate_access_2018("frame-support") {
Ok(path) => Ok(path),
Err(_) => generate_crate_access_2018("frame"),
}
.expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.")
.to_token_stream()
.to_string()
)
}]
#[proc_macro_attribute]
pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream {
let foreign_mod = parse_macro_input!(attr as ItemMod);
let mut internal_mod = parse_macro_input!(tokens as ItemMod);

// check that internal_mod is a pallet module
if !internal_mod.attrs.iter().any(|attr| {
if let Some(last_seg) = attr.path().segments.last() {
last_seg.ident == "pallet"
} else {
false
}
}) {
return Error::new(
internal_mod.ident.span(),
"`#[import_section]` can only be applied to a valid pallet module",
)
.to_compile_error()
.into()
}

if let Some(ref mut content) = internal_mod.content {
if let Some(foreign_content) = foreign_mod.content {
content.1.extend(foreign_content.1);
}
}

quote! {
#internal_mod
}
.into()
}
You are viewing a condensed version of this merge commit. You can view the full changes here.