use proc_macro2::Span;
use syn::{
Expr, Generics, Ident, Path, Token, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound,
parse_quote,
punctuated::Punctuated,
token::{Comma, Plus},
};
pub enum DocumentationStyle {
Function,
Method,
}
impl DocumentationStyle {
pub fn output(&self, func_name: &str) -> String {
match self {
DocumentationStyle::Function => format!("self::{func_name}"),
DocumentationStyle::Method => format!("Self::{func_name}"),
}
}
}
const SPAN_CODEC: &str = "${CODEC}";
const SPAN_ELSE: &str = "${ELSE}";
const SPAN_ELSE_HREF: &str = "${ELSE_HREF}";
const SPAN_IDENT: &str = "${IDENT}";
const SPAN_IDENT_HREF: &str = "${IDENT_HREF}";
const WAIT_FOR_REPLY_DOCS_TEMPLATE: &str = r#"
Same as [`${IDENT}`](${IDENT_HREF}), but the program
will interrupt until the reply is received.
Argument `reply_deposit: u64` used to provide gas for
future reply handling (skipped if zero).
${CODEC}
# See also
- [`${ELSE}`](${ELSE_HREF})
"#;
pub fn ident(s: &str) -> Ident {
Ident::new(s, Span::call_site())
}
pub fn with_suffix(i: &Ident, suffix: &str) -> Ident {
ident(&format!("{i}{suffix}"))
}
pub fn get_args(inputs: &Punctuated<syn::FnArg, syn::token::Comma>) -> Expr {
let idents = inputs.iter().filter_map(|param| {
if let syn::FnArg::Typed(pat_type) = param
&& let syn::Pat::Ident(pat_ident) = *pat_type.pat.clone()
{
return Some(pat_ident.ident);
}
None
});
let mut punctuated: Punctuated<syn::Ident, Comma> = Punctuated::new();
idents.for_each(|ident| punctuated.push(ident));
parse_quote!(( #punctuated ))
}
pub fn wait_for_reply_docs(name: String, style: DocumentationStyle) -> (String, String) {
let href = style.output(&name);
let docs = WAIT_FOR_REPLY_DOCS_TEMPLATE
.trim_start_matches('\n')
.replace(SPAN_IDENT, &name)
.replace(SPAN_IDENT_HREF, &href);
let for_reply = format!("{name}_for_reply");
let for_reply_href = style.output(&for_reply);
let for_reply_as = format!("{name}_for_reply_as");
let for_reply_as_href = style.output(&for_reply_as);
(
docs.replace(SPAN_ELSE, &for_reply_as)
.replace(SPAN_ELSE_HREF, &for_reply_as_href)
.replace(SPAN_CODEC, ""),
docs.replace(SPAN_ELSE, &for_reply)
.replace(SPAN_ELSE_HREF, &for_reply_href)
.replace(
SPAN_CODEC,
"\n\n The output should be decodable via SCALE codec.",
)
+ " - <https://docs.substrate.io/reference/scale-codec>",
)
}
pub fn append_generic(mut generics: Generics, ident: Ident, traits: Vec<Path>) -> Generics {
let mut bounds: Punctuated<TypeParamBound, Plus> = Punctuated::new();
for path in traits {
bounds.push_value(
TraitBound {
paren_token: None,
modifier: TraitBoundModifier::None,
lifetimes: None,
path,
}
.into(),
)
}
if !generics.params.is_empty() {
generics.params.push_punct(Token));
}
generics.params.push_value(
TypeParam {
attrs: Default::default(),
ident,
colon_token: Some(Token)),
bounds,
eq_token: None,
default: None,
}
.into(),
);
generics
}