Skip to main content

wowlab_common/markdown/
list.rs

1// #t(file: rust_alloc_in_loop) markdown list builder produces owned strings per element, unavoidable
2
3use std::fmt::Display;
4
5/// Bullet style used when rendering a [`List`].
6#[derive(Clone, Copy, Debug)]
7#[non_exhaustive]
8pub enum ListStyle {
9    Dash,
10    Asterisk,
11    Bullet,
12    Ordered,
13}
14
15/// Builder for rendering a formatted list in markdown.
16#[derive(Debug)]
17pub struct List {
18    items: Vec<Box<str>>,
19    style: ListStyle,
20}
21
22impl List {
23    #[must_use]
24    pub fn new() -> Self {
25        Self {
26            items: Vec::new(),
27            style: ListStyle::Dash,
28        }
29    }
30
31    #[must_use]
32    pub fn asterisk() -> Self {
33        Self {
34            items: Vec::new(),
35            style: ListStyle::Asterisk,
36        }
37    }
38
39    #[must_use]
40    pub fn bullet() -> Self {
41        Self {
42            items: Vec::new(),
43            style: ListStyle::Bullet,
44        }
45    }
46
47    #[must_use]
48    pub fn ordered() -> Self {
49        Self {
50            items: Vec::new(),
51            style: ListStyle::Ordered,
52        }
53    }
54
55    #[must_use]
56    pub fn item(mut self, text: impl Display) -> Self {
57        self.items.push(text.to_string().into_boxed_str());
58
59        self
60    }
61
62    #[must_use]
63    pub fn items<I, T>(mut self, items: I) -> Self
64    where
65        I: IntoIterator<Item = T>,
66        T: Display,
67    {
68        for item in items {
69            self.items.push(item.to_string().into_boxed_str());
70        }
71
72        self
73    }
74
75    #[must_use]
76    pub fn build(self) -> String {
77        self.items
78            .into_iter()
79            .enumerate()
80            .map(|(i, item)| match self.style {
81                ListStyle::Dash => format!("- {item}"),
82                ListStyle::Asterisk => format!("* {item}"),
83                ListStyle::Bullet => format!("• {item}"),
84                ListStyle::Ordered => format!("{}. {}", i + 1, item),
85            })
86            .collect::<Vec<_>>()
87            .join("\n")
88    }
89}
90impl Default for List {
91    fn default() -> Self {
92        Self::new()
93    }
94}