1use std::{
2 any::Any,
3 cell::{self, RefCell},
4 fmt,
5 rc::{Rc, Weak},
6};
7
8pub(super) trait ToMarkdown {
11 fn generate(&self, node: MdNodeRef);
15}
16
17pub(super) trait MdElement: fmt::Display + fmt::Debug + 'static {
23 fn id(&self) -> Option<&str>;
26
27 fn docs(&self) -> Option<&str>;
29
30 fn set_docs(&mut self, docs: &str);
32
33 fn as_any(&self) -> &dyn Any;
34 fn as_any_mut(&mut self) -> &mut dyn Any;
35}
36
37#[derive(Debug)]
44pub(super) struct MdNode {
45 content: Box<dyn MdElement>,
46 parent: Option<Weak<RefCell<MdNode>>>,
47 children: Vec<MdNodeRef>,
48}
49
50fn walk_ancestors(parent: Option<&Weak<RefCell<MdNode>>>, cb: &mut impl FnMut(MdNodeRef)) {
53 if let Some(parent) = parent.and_then(|x| x.upgrade()) {
54 cb(parent.clone().into());
55 walk_ancestors(parent.borrow().parent.as_ref(), cb)
56 }
57}
58
59impl MdNode {
60 fn new<T: MdElement + 'static>(item: T) -> Self {
61 Self {
62 content: Box::new(item),
63 parent: None,
64 children: vec![],
65 }
66 }
67
68 pub fn ancestors(&self) -> Vec<MdNodeRef> {
70 let mut ancestors = Vec::new();
71 walk_ancestors(self.parent.as_ref(), &mut |parent| ancestors.push(parent));
72 ancestors
73 }
74
75 pub fn children(&self) -> Vec<MdNodeRef> {
77 let mut children = self.children.clone();
78 for child in &self.children {
79 children.append(&mut child.borrow().children());
80 }
81 children
82 }
83}
84
85impl fmt::Display for MdNode {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 self.content.fmt(f)?;
88
89 for child in &self.children {
90 child.fmt(f)?;
91 }
92
93 Ok(())
94 }
95}
96
97#[derive(Debug)]
99pub(super) struct MdNodeRef(Rc<RefCell<MdNode>>);
100
101impl MdNodeRef {
102 pub fn new<T: MdElement + 'static>(item: T) -> Self {
103 Self(Rc::new(RefCell::new(MdNode::new(item))))
104 }
105
106 pub fn new_child<T: MdElement + 'static>(&self, item: T) -> Self {
109 let mut child_node = MdNode::new(item);
110 child_node.parent = Some(Rc::downgrade(&self.0));
111 let child_ref = Self(Rc::new(RefCell::new(child_node)));
112 self.borrow_mut().children.push(child_ref.clone());
113 child_ref
114 }
115
116 pub fn borrow(&self) -> cell::Ref<MdNode> {
117 self.0.borrow()
118 }
119
120 pub fn borrow_mut(&self) -> cell::RefMut<MdNode> {
121 self.0.borrow_mut()
122 }
123
124 pub fn any_ref(&self) -> cell::Ref<Box<dyn MdElement>> {
127 cell::Ref::map(self.borrow(), |b| &b.content)
128 }
129
130 pub fn any_ref_mut(&self) -> cell::RefMut<Box<dyn MdElement>> {
133 cell::RefMut::map(self.borrow_mut(), |b| &mut b.content)
134 }
135
136 pub fn content_ref_mut<T: MdElement + 'static>(&self) -> cell::RefMut<T> {
141 cell::RefMut::map(self.borrow_mut(), |b| {
142 let r = b.content.as_any_mut();
143 r.downcast_mut::<T>().expect("reference is not T type")
144 })
145 }
146}
147
148impl Clone for MdNodeRef {
149 fn clone(&self) -> Self {
150 Self(self.0.clone())
151 }
152}
153
154impl From<Rc<RefCell<MdNode>>> for MdNodeRef {
155 fn from(node: Rc<RefCell<MdNode>>) -> Self {
156 Self(node)
157 }
158}
159
160impl fmt::Display for MdNodeRef {
161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 self.borrow().fmt(f)
163 }
164}
165
166#[derive(Debug, Default)]
170pub(super) struct MdRoot;
171
172impl MdElement for MdRoot {
173 fn id(&self) -> Option<&str> {
174 None
175 }
176
177 fn docs(&self) -> Option<&str> {
178 None
179 }
180
181 fn set_docs(&mut self, _: &str) {}
182
183 fn as_any(&self) -> &dyn Any {
184 self
185 }
186
187 fn as_any_mut(&mut self) -> &mut dyn Any {
188 self
189 }
190}
191
192impl fmt::Display for MdRoot {
193 fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
194 Ok(())
195 }
196}
197
198#[derive(Debug, Clone, Copy)]
202pub(super) enum MdHeading {
203 Header { level: usize },
204 Bullet,
205}
206
207impl MdHeading {
208 pub fn new_header(level: usize) -> Self {
211 MdHeading::Header { level }
212 }
213
214 pub fn new_bullet() -> Self {
216 MdHeading::Bullet
217 }
218
219 pub fn new_level_down(&self) -> Self {
222 let mut copy = *self;
223 if let Self::Header { ref mut level } = &mut copy {
224 *level += 1;
225 }
226 copy
227 }
228}
229
230impl fmt::Display for MdHeading {
231 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232 let as_string = match self {
233 Self::Header { level } => "#".repeat(*level),
234 Self::Bullet => "-".to_owned(),
235 };
236 f.write_str(&as_string)
237 }
238}
239
240#[derive(Debug)]
249pub(super) struct MdSection {
250 pub heading: MdHeading,
251 pub id: Option<String>,
252 pub title: String,
253}
254
255impl MdSection {
256 pub fn new<S: AsRef<str>>(heading: MdHeading, title: S) -> Self {
257 Self {
258 heading,
259 id: None,
260 title: title.as_ref().to_owned(),
261 }
262 }
263}
264
265impl MdElement for MdSection {
266 fn id(&self) -> Option<&str> {
267 self.id.as_ref().map(|s| s.as_str())
268 }
269
270 fn docs(&self) -> Option<&str> {
271 None
272 }
273
274 fn set_docs(&mut self, _: &str) {}
275
276 fn as_any(&self) -> &dyn Any {
277 self
278 }
279
280 fn as_any_mut(&mut self) -> &mut dyn Any {
281 self
282 }
283}
284
285fn gen_link<S: AsRef<str>>(id: S) -> String {
286 format!("<a href=\"#{id}\" name=\"{id}\"></a>", id = id.as_ref())
287}
288
289impl fmt::Display for MdSection {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291 f.write_fmt(format_args!("{} ", self.heading))?;
292
293 if let Some(id) = &self.id {
294 f.write_fmt(format_args!("{} ", gen_link(id)))?;
295 }
296
297 writeln!(f, "{}", self.title)
298 }
299}
300
301#[derive(Debug)]
320pub(super) struct MdNamedType {
321 pub heading: MdHeading,
322 pub id: String,
323 pub name: String,
324 pub docs: String,
325 pub ty: Option<String>,
326}
327
328impl MdNamedType {
329 pub fn new<S: AsRef<str>>(heading: MdHeading, id: S, name: S, docs: S) -> Self {
330 Self {
331 heading,
332 id: id.as_ref().to_owned(),
333 name: name.as_ref().to_owned(),
334 docs: docs.as_ref().to_owned(),
335 ty: None,
336 }
337 }
338}
339
340impl MdElement for MdNamedType {
341 fn id(&self) -> Option<&str> {
342 Some(&self.id)
343 }
344
345 fn docs(&self) -> Option<&str> {
346 Some(&self.docs)
347 }
348
349 fn set_docs(&mut self, docs: &str) {
350 self.docs = docs.to_owned();
351 }
352
353 fn as_any(&self) -> &dyn Any {
354 self
355 }
356
357 fn as_any_mut(&mut self) -> &mut dyn Any {
358 self
359 }
360}
361
362impl fmt::Display for MdNamedType {
363 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364 f.write_fmt(format_args!(
365 "{heading} {link} `{name}`",
366 heading = self.heading,
367 link = gen_link(&self.id),
368 name = self.name,
369 ))?;
370
371 if let Some(tt) = &self.ty {
372 f.write_fmt(format_args!(": {}", tt))?;
373 }
374
375 writeln!(f, "\n{}", self.docs)
376 }
377}
378
379#[derive(Debug)]
402pub(super) struct MdFunc {
403 pub heading: MdHeading,
404 pub id: String,
405 pub name: String,
406 pub inputs: Vec<(String, String)>,
407 pub outputs: Vec<String>,
408 pub docs: String,
409}
410
411impl MdFunc {
412 pub fn new<S: AsRef<str>>(heading: MdHeading, id: S, name: S, docs: S) -> Self {
413 Self {
414 heading,
415 id: id.as_ref().to_owned(),
416 name: name.as_ref().to_owned(),
417 inputs: vec![],
418 outputs: vec![],
419 docs: docs.as_ref().to_owned(),
420 }
421 }
422}
423
424impl MdElement for MdFunc {
425 fn id(&self) -> Option<&str> {
426 Some(&self.id)
427 }
428
429 fn docs(&self) -> Option<&str> {
430 Some(&self.docs)
431 }
432
433 fn set_docs(&mut self, docs: &str) {
434 self.docs = docs.to_owned();
435 }
436
437 fn as_any(&self) -> &dyn Any {
438 self
439 }
440
441 fn as_any_mut(&mut self) -> &mut dyn Any {
442 self
443 }
444}
445
446impl fmt::Display for MdFunc {
447 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448 let inputs = self
450 .inputs
451 .iter()
452 .map(|(name, r#type)| format!("{}: {}", name, r#type))
453 .collect::<Vec<_>>()
454 .join(", ");
455 let outputs: Vec<_> = self
457 .outputs
458 .iter()
459 .map(|r#type| format!("{}", r#type))
460 .collect();
461 let outputs = match outputs.len() {
462 0 => "".to_owned(),
463 1 => format!(" -> {}", outputs[0]),
464 _ => format!(" -> ({})", outputs.join(", ")),
465 };
466 writeln!(f, "\n---\n")?;
468
469 f.write_fmt(format_args!(
470 "{heading} {link} `{name}({inputs}){outputs}`",
471 heading = self.heading,
472 link = gen_link(&self.id),
473 name = self.name,
474 inputs = inputs,
475 outputs = outputs,
476 ))?;
477
478 writeln!(f, "\n{}", self.docs)
479 }
480}