Repository: paritytech/substrate
File: primitives/api/proc-macro/src/impl_runtime_apis.rs (Rust)

Code before:
	attrs.push(attr);
}

// Fold implementation which processes function implementations in impl block for a trait. It is
// used to process `cfg_attr`s related to staging methods (e.g. `#[cfg_attr(feature =
// "enable-staging-api", api_version(99))]`). Replaces the `cfg_attr` attribute with a feature guard
// so that staging methods are added only for staging api implementations.
struct ApiImplItem<'a> {
	// Version of the trait where the `ImplItemFn` is located. Used for error reporting.
	trait_api_ver: &'a Option<(String, u64)>,
	// Span of the trait where the `ImplItemFn` is located. Used for error reporting.
	trait_span: Span,
	// All errors which occurred during folding
	errors: Vec<Error>,
}

impl<'a> ApiImplItem<'a> {
	pub fn new(trait_api_ver: &Option<(String, u64)>, trait_span: Span) -> ApiImplItem {
		ApiImplItem { trait_api_ver, trait_span, errors: Vec::new() }
	}

	pub fn process(&mut self, item: ItemImpl) -> Result<ItemImpl> {
		let res = self.fold_item_impl(item);

		if let Some(e) = self.errors.pop() {
			// TODO: what to do with the rest of the errors?
			return Err(e)
		}

		Ok(res)
	}
}

impl<'a> Fold for ApiImplItem<'a> {
	fn fold_impl_item_fn(&mut self, mut i: ImplItemFn) -> ImplItemFn {
		let v = extract_api_version(&i.attrs, i.span());

		let v = match v {
			Ok(ver) => ver,
			Err(e) => {
				// `api_version` attribute seems to be malformed
				self.errors.push(e);
				return fold::fold_impl_item_fn(self, i)
			},
		};

		if v.custom.is_some() {
			self.errors.push(Error::new(
				i.span(),
				"`api_version` attribute is not allowed `decl_runtime_api` method implementations",
			));

Review comment (suggestion):
I'm open for suggestions what to do in case there are multiple errors here. Atm just the first one is returned, which is okay-ish.
The alternative is to combine them, but I think it will look ugly.

Code after:

		let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone();
		let trait_ = extend_with_runtime_decl_path(trait_);
		// If the trait api contains feature gated version - there are staging methods in it. Handle
		// them explicitly here by adding staging implementation with `#cfg(feature = ...)` and
		// stable implementation with `#[cfg(not(feature = ...))]`.
		if let Some(feature_gated) = trait_api_ver.feature_gated {
			let mut feature_gated_impl = impl_.clone();
			add_feature_guard(&mut feature_gated_impl.attrs, &feature_gated.0, true);
			feature_gated_impl.trait_.as_mut().unwrap().1 =
				extend_with_api_version(trait_.clone(), Some(feature_gated.1));

			impls_prepared.push(feature_gated_impl);

			// Finally add `#[cfg(not(feature = ...))]` for the stable implementation (which is
			// generated outside this if).
			add_feature_guard(&mut impl_.attrs, &feature_gated.0, false);
		}

		// Generate stable trait implementation.
		let trait_ = extend_with_api_version(trait_, trait_api_ver.custom);
		impl_.trait_.as_mut().unwrap().1 = trait_;
		impls_prepared.push(impl_);
	}

	Ok(quote!( #( #impls_prepared )* ))
}

/// Auxiliary data structure that is used to convert `impl Api for Runtime` to
/// `impl Api for RuntimeApi`.
/// This requires us to replace the runtime `Block` with the node `Block`,
/// `impl Api for Runtime` with `impl Api for RuntimeApi` and replace the method implementations
/// with code that calls into the runtime.
struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
	runtime_block: &'a TypePath,
}

impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
	/// Process the given item implementation.
	fn process(mut self, input: ItemImpl) -> ItemImpl {
		let mut input = self.fold_item_impl(input);

		let crate_ = generate_crate_access();

		// Delete all functions, because all of them are default implemented by
		// `decl_runtime_apis!`. We only need to implement the `__runtime_api_internal_call_api_at`
		// function.
		input.items.clear();
		input.items.push(parse_quote! {
			fn __runtime_api_internal_call_api_at(
				&self,