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

Code before:

			// Add `#[cfg(not(feature ...))]` to the initial attributes. If the staging feature flag
			// is not set we want to set the stable api version
			add_feature_guard(&mut attrs, &feature_gated.0, false);
		}

		// Now add the stable api version to the versions list. If the api has got staging functions
		// there might be a `#[cfg(not(feature ...))]` attribute attached to the stable version.
		let base_api_version = quote!( #path VERSION );
		let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version);
		populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c);
	}

	Ok(quote!(
		const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);

		#( #sections )*
	))
}

/// The implementation of the `impl_runtime_apis!` macro.
pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	// Parse all impl blocks
	let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);

	impl_runtime_apis_impl_inner(&api_impls)
		.unwrap_or_else(|e| e.to_compile_error())
		.into()
}

fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
	let dispatch_impl = generate_dispatch_function(api_impls)?;
	let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
	let base_runtime_api = generate_runtime_api_base_structures()?;
	let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
	let wasm_interface = generate_wasm_interface(api_impls)?;
	let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;

	#[cfg(feature = "frame-metadata")]
	let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
	#[cfg(not(feature = "frame-metadata"))]
	let runtime_metadata = quote!();

	let impl_ = quote!(
		#base_runtime_api

		#api_impls_for_runtime

		#api_impls_for_runtime_api

		#runtime_api_versions

Review comment (suggestion):
```suggestion
	/// Corresponds to `#[api_version(X)]` attribute.
	pub custom: Option<u64>,
```

Code after:

		// If there is a cfg attribute containing api_version - save if for processing
		if let (Some(feature_name), Some(api_version)) = (feature_name, api_version) {
			cfg_api_version_attr.push((feature_name, api_version, cfg_attr.span()));
		}
	}

	if cfg_api_version_attr.len() > 1 {
		let mut err = Error::new(span, format!("Found multiple feature gated api versions (cfg attribute with nested `{}` attribute). This is not supported.", API_VERSION_ATTRIBUTE));
		for (_, _, attr_span) in cfg_api_version_attr {
			err.combine(Error::new(attr_span, format!("`{}` found here", API_VERSION_ATTRIBUTE)));
		}

		return Err(err)
	}

	Ok(cfg_api_version_attr
		.into_iter()
		.next()
		.map(|(feature, name, _)| (feature, name)))
}

/// Represents an API version.
struct ApiVersion {
	/// Corresponds to `#[api_version(X)]` attribute.
	pub custom: Option<u64>,
	/// Corresponds to `#[cfg_attr(feature = "enable-staging-api", api_version(99))]`
	/// attribute. `String` is the feature name, `u64` the staging api version.
	pub feature_gated: Option<(String, u64)>,
}

// Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors.
// Returns:
// - Err if the version is malformed
// - `ApiVersion` on success. If a version is set or not is determined by the fields of `ApiVersion`
fn extract_api_version(attrs: &Vec<Attribute>, span: Span) -> Result<ApiVersion> {
	// First fetch all `API_VERSION_ATTRIBUTE` values (should be only one)
	let api_ver = attrs
		.iter()
		.filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE))
		.collect::<Vec<_>>();

	if api_ver.len() > 1 {
		return Err(Error::new(
			span,
			format!(
				"Found multiple #[{}] attributes for an API implementation. \
				Each runtime API can have only one version.",
				API_VERSION_ATTRIBUTE
			),
		))