use syn::{
Fields,
ForeignItemStatic,
ImplItemConst,
ItemConst,
ItemStatic,
TraitItemConst,
Visibility,
};
use crate::directives::directive_options::{DirectiveOption, DirectiveVisibility, IndexEntryType};
use crate::directives::{extract_doc_from_attrs, Directive};
use crate::formats::{MdContent, MdDirective, RstContent, RstDirective};
use crate::nodes::{nodes_for_type, Node};
#[derive(Clone, Debug)]
pub struct VariableDirective {
pub(crate) name: String,
pub(crate) ident: String,
pub(crate) options: Vec<DirectiveOption>,
pub(crate) content: Vec<String>,
}
macro_rules! var_from_item {
($item:expr, $parent_path:expr, $vis:expr, $inherited:expr, $prefix:expr, $index:expr) => {{
let name = format!("{}::{}", $parent_path, &$item.ident);
let mut nodes = vec![
Node::Keyword($prefix),
Node::Space,
Node::Name($item.ident.to_string()),
Node::Punctuation(": "),
];
nodes.extend(nodes_for_type(&$item.ty));
let options = vec![
DirectiveOption::Index($index),
DirectiveOption::Vis(DirectiveVisibility::effective_visibility(&$vis, $inherited)),
DirectiveOption::Toc(format!("{} {}", $prefix, &$item.ident)),
DirectiveOption::Layout(nodes),
];
VariableDirective {
name,
ident: $item.ident.to_string(),
options,
content: extract_doc_from_attrs(&$item.attrs),
}
}};
}
impl VariableDirective {
const DIRECTIVE_NAME: &'static str = "variable";
pub(crate) fn from_fields(
parent_path: &str,
fields: &Fields,
inherited_visibility: &Option<&Visibility>,
index_entry_type: IndexEntryType,
) -> Vec<Self> {
if let Fields::Named(named_fields) = fields {
named_fields
.named
.iter()
.map(|f| {
let mut nodes = vec![
Node::Name(f.ident.as_ref().unwrap().to_string()),
Node::Punctuation(": "),
];
nodes.extend(nodes_for_type(&f.ty));
let options = vec![
DirectiveOption::Index(index_entry_type),
DirectiveOption::Vis(DirectiveVisibility::effective_visibility(
&f.vis,
inherited_visibility,
)),
DirectiveOption::Toc(format!("{}", f.ident.as_ref().unwrap())),
DirectiveOption::Layout(nodes),
];
VariableDirective {
name: format!("{}::{}", parent_path, f.ident.as_ref().unwrap()),
ident: f.ident.as_ref().unwrap().to_string(),
options,
content: extract_doc_from_attrs(&f.attrs),
}
})
.collect()
}
else {
Vec::new()
}
}
pub(crate) fn from_static(parent_path: &str, item: &ItemStatic) -> Directive {
Directive::Variable(var_from_item!(
item,
parent_path,
item.vis,
&None,
"static",
IndexEntryType::Normal
))
}
pub(crate) fn from_const(parent_path: &str, item: &ItemConst) -> Directive {
Directive::Variable(var_from_item!(
item,
parent_path,
item.vis,
&None,
"const",
IndexEntryType::Normal
))
}
pub(crate) fn from_impl_const(
parent_path: &str,
item: &ImplItemConst,
inherited_visibility: &Option<&Visibility>,
) -> Directive {
Directive::Variable(var_from_item!(
item,
parent_path,
item.vis,
inherited_visibility,
"const",
IndexEntryType::None
))
}
pub(crate) fn from_trait_const(
parent_path: &str,
item: &TraitItemConst,
inherited_visibility: &Option<&Visibility>,
) -> Directive {
Directive::Variable(var_from_item!(
item,
parent_path,
Visibility::Inherited,
inherited_visibility,
"const",
IndexEntryType::None
))
}
pub(crate) fn from_extern_static(parent_path: &str, item: &ForeignItemStatic) -> Directive {
Directive::Variable(var_from_item!(
item,
parent_path,
item.vis,
&None,
"extern static",
IndexEntryType::Normal
))
}
pub(crate) fn directive_visibility(&self) -> &DirectiveVisibility {
if let DirectiveOption::Vis(v) = &self.options[1] {
return v;
}
unreachable!("Variable: order of options changed")
}
pub(crate) fn change_parent(&mut self, new_parent: &str) {
self.name = format!("{new_parent}::{}", self.ident);
}
}
impl RstDirective for VariableDirective {
fn get_rst_text(self, level: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
if self.directive_visibility() > max_visibility {
return vec![];
}
let content_indent = Self::make_indent(level + 1);
let mut text =
Self::make_rst_header(Self::DIRECTIVE_NAME, &self.name, &self.options, level);
text.extend(self.content.get_rst_text(&content_indent));
text
}
}
impl MdDirective for VariableDirective {
fn get_md_text(self, fence_size: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
if self.directive_visibility() > max_visibility {
return vec![];
}
let fence = Self::make_fence(fence_size);
let mut text =
Self::make_md_header(Self::DIRECTIVE_NAME, &self.name, &self.options, &fence);
text.extend(self.content.get_md_text());
text.push(fence);
text
}
}