sphinx_rustdocgen/directives/
impl_directive.rs1use syn::{ItemImpl, Visibility};
20
21use crate::directives::directive_options::{DirectiveOption, DirectiveVisibility, IndexEntryType};
22use crate::directives::{extract_doc_from_attrs, order_items, Directive};
23use crate::formats::{MdContent, MdDirective, RstContent, RstDirective};
24use crate::nodes::{
25 nodes_for_generics,
26 nodes_for_path,
27 nodes_for_type,
28 nodes_for_where_clause,
29 type_name,
30 Node,
31};
32
33#[derive(Clone, Debug)]
35pub struct ImplDirective {
36 pub(crate) name: String,
38 pub(crate) self_ty: String,
40 pub(crate) resolved_self_ty: String,
42 pub(crate) trait_: Option<String>,
44 pub(crate) resolved_trait: Option<String>,
46 pub(crate) options: Vec<DirectiveOption>,
48 pub(crate) content: Vec<String>,
50 pub(crate) items: Vec<Directive>,
52}
53
54fn nodes_for_impl(item: &ItemImpl) -> Vec<Node> {
56 let mut nodes = vec![];
57 if item.unsafety.is_some() {
58 nodes.extend_from_slice(&[Node::Keyword("unsafe"), Node::Space]);
59 }
60 nodes.extend_from_slice(&[Node::Keyword("impl")]);
61 nodes.extend(nodes_for_generics(&item.generics));
62 nodes.push(Node::Space);
63 if let Some((bang, path, _)) = &item.trait_ {
64 if bang.is_some() {
65 nodes.push(Node::Operator("!"));
66 }
67 nodes.extend(nodes_for_path(path));
68 nodes.extend_from_slice(&[Node::Space, Node::Keyword("for"), Node::Space]);
69 }
70 nodes.extend(nodes_for_type(&item.self_ty));
71 if let Some(wc) = &item.generics.where_clause {
72 nodes.extend(nodes_for_where_clause(wc));
73 }
74 nodes
75}
76
77impl ImplDirective {
78 const DIRECTIVE_NAME: &'static str = "impl";
79
80 pub(crate) fn from_item(
81 parent_path: &str,
82 item: &ItemImpl,
83 inherited_visibility: &Option<&Visibility>,
84 ) -> Self {
85 let self_ty = type_name(&item.self_ty);
86
87 let mut trait_ = String::new();
88 if let Some((bang, path, _)) = &item.trait_ {
89 if bang.is_some() {
90 trait_ += "!";
91 }
92 trait_ += &*path.segments.last().unwrap().ident.to_string();
93 };
94
95 let options = vec![
96 DirectiveOption::Index(IndexEntryType::None),
97 DirectiveOption::Vis(DirectiveVisibility::Pub), DirectiveOption::Layout(nodes_for_impl(item)),
99 if trait_.is_empty() {
100 DirectiveOption::Toc(format!("impl {self_ty}"))
101 }
102 else {
103 DirectiveOption::Toc(format!("impl {trait_} for {self_ty}"))
104 },
105 ];
106
107 let name = if trait_.is_empty() {
108 format!("{parent_path}::{self_ty}")
109 }
110 else {
111 format!("{parent_path}::{self_ty}::{trait_}")
112 };
113 let items = Directive::from_impl_items(&name, item.items.iter(), inherited_visibility);
114 ImplDirective {
115 name,
116 self_ty,
117 resolved_self_ty: String::new(),
118 trait_: if trait_.is_empty() {
119 None
120 }
121 else {
122 Some(trait_)
123 },
124 resolved_trait: None,
125 options,
126 content: extract_doc_from_attrs(&item.attrs),
127 items,
128 }
129 }
130
131 pub(crate) fn directive_visibility(&self) -> &DirectiveVisibility {
133 if let DirectiveOption::Vis(v) = &self.options[1] {
134 return v;
135 }
136 unreachable!("Impl: order of options changed")
137 }
138
139 pub(crate) fn set_directive_visibility(&mut self, visibility: &DirectiveVisibility) {
140 self.options[1] = DirectiveOption::Vis(*visibility)
141 }
142
143 pub(crate) fn change_parent(&mut self, new_parent: &str) {
145 if let Some(t) = &self.trait_ {
146 self.name = format!("{new_parent}::{}::{t}", self.self_ty)
147 }
148 else {
149 self.name = format!("{new_parent}::{}", self.self_ty);
150 }
151 for item in &mut self.items {
152 item.change_parent(&self.name);
153 }
154 }
155
156 pub(crate) fn for_item(&self, name: &str) -> bool {
157 name == self.name
158 || self.name.starts_with(&format!("{}::", name))
159 || name == self.resolved_self_ty
160 }
161
162 pub(crate) fn for_trait(&self, name: &str, parent_name: &str) -> bool {
163 match &self.trait_ {
164 Some(trait_) => {
165 name == format!("{parent_name}::{trait_}") || name == self.resolved_trait.as_ref().unwrap_or(&String::new())
167 }
168 _ => false,
169 }
170 }
171}
172
173impl RstDirective for ImplDirective {
174 fn get_rst_text(self, level: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
175 let content_indent = Self::make_content_indent(level + 1);
176
177 let mut text =
178 Self::make_rst_header(Self::DIRECTIVE_NAME, &self.name, &self.options, level);
179 text.extend(self.content.get_rst_text(&content_indent));
180
181 for (section, items) in order_items(self.items) {
182 text.extend(Self::make_rst_section(
183 section,
184 level,
185 items,
186 max_visibility,
187 ));
188 }
189
190 text
191 }
192}
193
194impl MdDirective for ImplDirective {
195 fn get_md_text(self, fence_size: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
196 let fence = Self::make_fence(fence_size);
197
198 let mut text =
199 Self::make_md_header(Self::DIRECTIVE_NAME, &self.name, &self.options, &fence);
200 text.extend(self.content.get_md_text());
201
202 for (section, items) in order_items(self.items) {
203 text.extend(Self::make_md_section(
204 section,
205 fence_size,
206 items,
207 max_visibility,
208 ));
209 }
210
211 text.push(fence);
212 text
213 }
214
215 fn fence_size(&self) -> usize {
216 Self::calc_fence_size(&self.items)
217 }
218}