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

Code before:
}

fn extend_with_api_version(mut trait_: Path, version: Option<u64>) -> Path {
	let version = if let Some(v) = version {
		v
	} else {
		// nothing to do
		return trait_
	};

	let trait_name = &mut trait_
		.segments
		.last_mut()
		.expect("Trait path should always contain at least one item; qed")
		.ident;
	*trait_name = versioned_trait_name(trait_name, version);

	trait_
}

// Adds a `#[cfg( feature = ...)]` attribute to attributes. Parameters:
// feature_name - name of the feature
// t - positive or negative feature guard.
//		true => `#[cfg(feature = ...)]`
//		false => `#[cfg(not(feature = ...))]`
fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, t: bool) {
	let attr = match t {
		true => parse_quote!(#[cfg(feature = #feature_name)]),
		false => parse_quote!(#[cfg(not(feature = #feature_name))]),
	};
	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() }
	}


Review comment (suggestion):
```suggestion
fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
```

Code after:
		.expect("Trait path should always contain at least one item; qed")
		.ident;
	*trait_name = versioned_trait_name(trait_name, version);

	trait_
}

/// Adds a feature guard to `attributes`.
///
/// Depending on `enable`, the feature guard either enables ('feature = "something"`) or disables
/// (`not(feature = "something")`).
fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
	let attr = match enable {
		true => parse_quote!(#[cfg(feature = #feature_name)]),
		false => parse_quote!(#[cfg(not(feature = #feature_name))]),
	};
	attrs.push(attr);
}

/// Generates the implementations of the apis for the runtime.
fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
	let mut impls_prepared = Vec::new();

	// We put `runtime` before each trait to get the trait that is intended for the runtime and
	// we put the `RuntimeBlock` as first argument for the trait generics.
	for impl_ in impls.iter() {
		let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;

		let mut impl_ = impl_.clone();
		impl_.attrs = filter_cfg_attrs(&impl_.attrs);

		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);