sphinx_rustdocgen/directives/
trait_directive.rs1use syn::{ItemTrait, ItemTraitAlias};
20
21use crate::directives::directive_options::{DirectiveOption, DirectiveVisibility, IndexEntryType};
22use crate::directives::{extract_doc_from_attrs, order_items, Directive, ImplDirective};
23use crate::formats::{MdContent, MdDirective, RstContent, RstDirective};
24use crate::nodes::{nodes_for_generics, nodes_for_where_clause, Node};
25
26#[derive(Clone, Debug)]
28pub struct TraitDirective {
29 pub(crate) name: String,
31 pub(crate) ident: String,
33 pub(crate) options: Vec<DirectiveOption>,
35 pub(crate) content: Vec<String>,
37 pub(crate) items: Vec<Directive>,
39 pub(crate) impls: Vec<ImplDirective>,
41}
42
43impl TraitDirective {
44 const DIRECTIVE_NAME: &'static str = "trait";
45
46 pub(crate) fn from_item(parent_path: &str, item: &ItemTrait) -> Directive {
49 let name = format!("{}::{}", parent_path, item.ident);
50
51 let mut nodes = vec![];
52 if item.unsafety.is_some() {
53 nodes.push(Node::Keyword("unsafe"));
54 nodes.push(Node::Space);
55 }
56 nodes.push(Node::Keyword(Self::DIRECTIVE_NAME));
57 nodes.push(Node::Space);
58 nodes.push(Node::Name(item.ident.to_string()));
59 nodes.extend(nodes_for_generics(&item.generics));
60 if let Some(wc) = &item.generics.where_clause {
61 nodes.extend(nodes_for_where_clause(wc));
62 }
63
64 let options = vec![
65 DirectiveOption::Index(IndexEntryType::WithSubEntries),
66 DirectiveOption::Vis(DirectiveVisibility::from(&item.vis)),
67 DirectiveOption::Layout(nodes),
68 ];
69
70 let items = Directive::from_trait_items(&name, item.items.iter(), &Some(&item.vis));
71
72 Directive::Trait(TraitDirective {
73 name,
74 ident: item.ident.to_string(),
75 options,
76 content: extract_doc_from_attrs(&item.attrs),
77 items,
78 impls: vec![],
79 })
80 }
81
82 pub(crate) fn from_alias(parent_path: &str, alias: &ItemTraitAlias) -> Directive {
85 let name = format!("{}::{}", parent_path, alias.ident);
86
87 let mut nodes = vec![
88 Node::Keyword(Self::DIRECTIVE_NAME),
89 Node::Space,
90 Node::Name(alias.ident.to_string()),
91 ];
92 nodes.extend(nodes_for_generics(&alias.generics));
93 if let Some(wc) = &alias.generics.where_clause {
94 nodes.extend(nodes_for_where_clause(wc));
95 }
96
97 let options = vec![
98 DirectiveOption::Index(IndexEntryType::Normal),
99 DirectiveOption::Vis(DirectiveVisibility::from(&alias.vis)),
100 DirectiveOption::Layout(nodes),
101 ];
102
103 Directive::Trait(TraitDirective {
104 name,
105 ident: alias.ident.to_string(),
106 options,
107 content: extract_doc_from_attrs(&alias.attrs),
108 items: vec![],
109 impls: vec![],
110 })
111 }
112
113 pub(crate) fn directive_visibility(&self) -> &DirectiveVisibility {
115 if let DirectiveOption::Vis(v) = &self.options[1] {
116 return v;
117 }
118 unreachable!("Trait: order of options changed")
119 }
120
121 pub(crate) fn change_parent(&mut self, new_parent: &str) {
123 self.name = format!("{new_parent}::{}", self.ident);
124 for item in &mut self.items {
125 item.change_parent(&self.name);
126 }
127 for impl_ in &mut self.impls {
128 impl_.change_parent(new_parent);
129 }
130 }
131
132 pub(crate) fn add_impl(&mut self, mut impl_: ImplDirective) {
140 impl_.change_parent(&self.name[0..self.name.rfind("::").unwrap()]);
141 impl_.set_directive_visibility(self.directive_visibility());
142 self.impls.push(impl_);
143 }
144}
145
146impl RstDirective for TraitDirective {
147 fn get_rst_text(self, level: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
148 if self.directive_visibility() > max_visibility {
149 return vec![];
150 }
151 let content_indent = Self::make_content_indent(level);
152
153 let mut text =
154 Self::make_rst_header(Self::DIRECTIVE_NAME, &self.name, &self.options, level);
155 text.extend(self.content.get_rst_text(&content_indent));
156
157 for (section, items) in order_items(self.items) {
158 text.extend(Self::make_rst_section(
159 section,
160 level,
161 items,
162 max_visibility,
163 ));
164 }
165
166 text.extend(Self::make_rst_section(
167 "Implemented for",
168 level,
169 self.impls.into_iter().map(Directive::Impl).collect(),
170 max_visibility,
171 ));
172
173 text
174 }
175}
176
177impl MdDirective for TraitDirective {
178 fn get_md_text(self, fence_size: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
179 if self.directive_visibility() > max_visibility {
180 return vec![];
181 }
182 let fence = Self::make_fence(fence_size);
183
184 let mut text =
185 Self::make_md_header(Self::DIRECTIVE_NAME, &self.name, &self.options, &fence);
186 text.extend(self.content.get_md_text());
187
188 for (section, items) in order_items(self.items) {
189 text.extend(Self::make_md_section(
190 section,
191 fence_size,
192 items,
193 max_visibility,
194 ));
195 }
196
197 text.extend(Self::make_md_section(
198 "Implemented for",
199 fence_size,
200 self.impls.into_iter().map(Directive::Impl).collect(),
201 max_visibility,
202 ));
203
204 text.push(fence);
205 text
206 }
207
208 fn fence_size(&self) -> usize {
209 [
210 Self::calc_fence_size(&self.items),
211 match self.impls.iter().map(ImplDirective::fence_size).max() {
212 Some(s) => s + 1,
213 None => 3,
214 },
215 ]
216 .into_iter()
217 .max()
218 .unwrap()
219 }
220}