1use std::fmt::{self, Write};
32
33use crate::{Block, Doc, Formatter, MethodParam, Type, Visibility};
34
35#[derive(Debug, Clone)]
37pub struct Method {
38 name: String,
40
41 visibility: Visibility,
43
44 doc: Option<Doc>,
46
47 params: Vec<MethodParam>,
49
50 ret: Type,
52
53 is_static: bool,
55
56 is_inline: bool,
58
59 is_virtual: bool,
61
62 is_pure: bool,
64
65 is_override: bool,
67
68 is_const: bool,
70
71 is_inside: bool,
73
74 body: Block,
76}
77
78impl Method {
79 pub fn new(name: &str, ret: Type) -> Self {
81 Self::with_string(String::from(name), ret)
82 }
83
84 pub fn with_string(name: String, ret: Type) -> Self {
85 Self {
86 name,
87 doc: None,
88 visibility: Visibility::Private,
89 params: Vec::new(),
90 ret,
91 is_static: false,
92 is_inline: false,
93 is_virtual: false,
94 is_pure: false,
95 is_override: false,
96 is_const: false,
97 is_inside: false,
98 body: Block::new(),
99 }
100 }
101
102 pub fn name(&self) -> &str {
104 &self.name
105 }
106
107 pub fn to_type(&self) -> Type {
109 panic!("needs to implement a corresponding type.")
110 }
111
112 pub fn doc_str(&mut self, doc: &str) -> &mut Self {
114 if let Some(d) = &mut self.doc {
115 d.add_text(doc);
116 } else {
117 self.doc = Some(Doc::with_str(doc));
118 }
119 self
120 }
121
122 pub fn add_doc(&mut self, doc: Doc) -> &mut Self {
124 self.doc = Some(doc);
125 self
126 }
127
128 pub fn set_visibility(&mut self, vis: Visibility) -> &mut Self {
130 self.visibility = vis;
131 self
132 }
133
134 pub fn is_public(&self) -> bool {
136 self.visibility == Visibility::Public
137 }
138
139 pub fn is_protected(&self) -> bool {
141 self.visibility == Visibility::Protected
142 }
143
144 pub fn is_private(&self) -> bool {
146 self.visibility == Visibility::Private || self.visibility == Visibility::Default
147 }
148
149 pub fn set_public(&mut self) -> &mut Self {
151 self.set_visibility(Visibility::Public)
152 }
153
154 pub fn set_protected(&mut self) -> &mut Self {
156 self.set_visibility(Visibility::Protected)
157 }
158
159 pub fn set_private(&mut self) -> &mut Self {
161 self.set_visibility(Visibility::Private)
162 }
163
164 pub fn push_param(&mut self, arg: MethodParam) -> &mut Self {
166 self.params.push(arg);
167 self
168 }
169
170 pub fn new_param(&mut self, name: &str, ty: Type) -> &mut MethodParam {
172 self.push_param(MethodParam::new(name, ty));
173 self.params.last_mut().unwrap()
174 }
175
176 pub fn param_by_name(&self, name: &str) -> Option<&MethodParam> {
178 self.params.iter().find(|f| f.name() == name)
179 }
180
181 pub fn param_by_name_mut(&mut self, name: &str) -> Option<&mut MethodParam> {
183 self.params.iter_mut().find(|f| f.name() == name)
184 }
185
186 pub fn param_by_idx(&self, idx: usize) -> Option<&MethodParam> {
188 self.params.get(idx)
189 }
190
191 pub fn param_by_idx_mut(&mut self, idx: usize) -> Option<&mut MethodParam> {
193 self.params.get_mut(idx)
194 }
195
196 pub fn toggle_override(&mut self, val: bool) -> &mut Self {
202 self.is_override = val;
203 self
204 }
205
206 pub fn set_override(&mut self) -> &mut Self {
208 self.toggle_override(true)
209 }
210
211 pub fn toggle_const(&mut self, val: bool) -> &mut Self {
217 self.is_const = val;
218 self
219 }
220
221 pub fn set_const(&mut self) -> &mut Self {
223 self.toggle_const(true)
224 }
225
226 pub fn toggle_virtual(&mut self, val: bool) -> &mut Self {
232 if !val {
233 self.is_pure = false;
234 }
235 self.is_virtual = val;
236 self
237 }
238
239 pub fn set_virtual(&mut self) -> &mut Self {
241 self.toggle_virtual(true)
242 }
243
244 pub fn toggle_pure(&mut self, val: bool) -> &mut Self {
250 if val {
251 self.body.clear();
252 self.is_virtual = true
253 }
254 self.is_pure = val;
255 self
256 }
257
258 pub fn set_pure(&mut self) -> &mut Self {
260 self.toggle_pure(true)
261 }
262
263 pub fn toggle_static(&mut self, val: bool) -> &mut Self {
269 self.is_static = val;
270 self
271 }
272
273 pub fn set_static(&mut self) -> &mut Self {
275 self.toggle_static(true)
276 }
277
278 pub fn toggle_inline(&mut self, val: bool) -> &mut Self {
284 self.is_inline = val;
285 self
286 }
287
288 pub fn set_inline(&mut self) -> &mut Self {
290 self.toggle_inline(true)
291 }
292
293 pub fn toggle_inside_def(&mut self, val: bool) -> &mut Self {
295 self.is_inside = val;
296 self
297 }
298
299 pub fn set_inside_def(&mut self) -> &mut Self {
301 self.toggle_inside_def(true)
302 }
303
304 pub fn set_body(&mut self, body: Block) -> &mut Self {
306 if !body.is_empty() {
307 self.is_pure = false;
308 }
309 self.body = body;
310 self
311 }
312
313 pub fn body(&mut self) -> &mut Block {
315 &mut self.body
316 }
317
318 pub fn do_fmt(&self, fmt: &mut Formatter<'_>, decl_only: bool) -> fmt::Result {
320 if !self.body.is_empty() | self.doc.is_some() {
321 writeln!(fmt)?;
322 }
323
324 if let Some(ref docs) = self.doc {
325 docs.fmt(fmt)?;
326 }
327
328 if self.is_static && decl_only {
329 write!(fmt, "static ")?;
330 }
331
332 if self.is_inline {
333 write!(fmt, "inline ")?;
334 }
335
336 if self.is_virtual && decl_only {
337 write!(fmt, "virtual ")?;
338 }
339
340 self.ret.fmt(fmt)?;
341 if decl_only {
342 write!(fmt, " {}", self.name)?;
343 } else {
344 fmt.write_scoped_name(self.name.as_str())?;
345 }
346 if self.params.is_empty() {
347 write!(fmt, "(void)")?;
348 } else {
349 write!(fmt, "(")?;
350 for (i, arg) in self.params.iter().enumerate() {
351 if i != 0 {
352 write!(fmt, ", ")?;
353 }
354 arg.fmt(fmt)?;
355 }
356 write!(fmt, ")")?;
357 }
358
359 if self.is_const && decl_only {
360 write!(fmt, " const")?;
361 }
362
363 if self.is_override && decl_only {
364 write!(fmt, " override")?;
365 }
366
367 if self.body.is_empty() && self.is_pure && decl_only {
368 return write!(fmt, " = 0;");
369 }
370
371 if self.body.is_empty() || (decl_only && !(self.is_inside || self.is_inline)) {
374 return writeln!(fmt, ";");
375 }
376
377 fmt.block(|f| self.body.fmt(f))?;
378 writeln!(fmt)
379 }
380
381 pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
383 self.do_fmt(fmt, false)
384 }
385
386 pub fn fmt_decl(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
388 self.do_fmt(fmt, true)
389 }
390
391 pub fn fmt_def(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
393 if self.is_inline || self.is_inside {
395 return Ok(());
396 }
397 self.do_fmt(fmt, false)
398 }
399}