use proc_macro2::{Span, TokenStream};
use syn::{parse::Parser, Attribute};
use crate::implementation::{Contract, ContractMode};
pub(crate) fn generate_attributes(contracts: &[Contract]) -> Vec<Attribute> {
let mut attrs = vec![];
fn make_attribute(content: &str) -> Attribute {
let span = Span::call_site();
let content_str = syn::LitStr::new(content, span);
let toks: TokenStream = quote::quote_spanned!( span=> #[doc = #content_str] );
let parser = Attribute::parse_outer;
let mut attributes = parser.parse2(toks).unwrap();
attributes.remove(0)
}
fn print_stream(stream: &TokenStream) -> String {
stream.to_string()
}
attrs.push(make_attribute("# Contracts"));
for contract in contracts {
let ty = contract.ty;
let mode = match contract.mode {
ContractMode::Always => None,
ContractMode::Disabled => None,
ContractMode::Debug => Some("debug"),
ContractMode::Test => Some("test"),
ContractMode::LogOnly => None,
};
if let Some(desc) = &contract.desc {
let header_txt = if let Some(name) = mode {
format!("{} - {}: {}", ty.message_name(), name, desc)
} else {
format!("{}: {}", ty.message_name(), desc)
};
attrs.push(make_attribute(&header_txt));
for (_assert, stream) in contract.assertions.iter().zip(contract.streams.iter()) {
attrs.push(make_attribute(&format!(" - `{}`", print_stream(stream))));
}
attrs.push(make_attribute(""));
} else {
for stream in &contract.streams {
let doc_str = if let Some(name) = mode {
format!(
"{} - {}: `{}`",
ty.message_name(),
name,
print_stream(stream)
)
} else {
format!("{}: `{}`", ty.message_name(), print_stream(stream))
};
attrs.push(make_attribute(&doc_str));
attrs.push(make_attribute(""));
}
}
}
attrs
}