resume_generator/
project.rs1crate::ix!();
2
3#[derive(Debug,Clone)]
4pub struct ResumeProjects(Vec<ResumeProject>);
5
6impl From<Vec<ResumeProject>> for ResumeProjects {
7 fn from(x: Vec<ResumeProject>) -> Self {
8 Self(x)
9 }
10}
11
12impl ResumeProjects {
13 delegate!{
14 to self.0 {
15 pub fn is_empty(&self) -> bool;
16 pub fn len(&self) -> usize;
17 }
18 }
19}
20
21impl LatexSectionItem for ResumeProjects {
22
23 fn render_latex_snippet(&self) -> String {
24
25 let mut result = String::new();
26
27 if !self.0.is_empty() {
28
29 result.push_str(r#"\section*{Projects}\begin{itemize}[leftmargin=*, label=-]"#);
30
31 for project in &self.0 {
32 result.push_str(&project.render_latex_snippet());
33 }
34
35 result.push_str(r#"\end{itemize}\vspace{2pt}"#);
36 }
37
38 result
39 }
40}
41
42#[derive(Debug,Clone)]
43pub struct ResumeProject {
44 title: String,
45 dates: DateRange,
46 description: Vec<String>,
47}
48
49impl LatexSectionItem for ResumeProject {
50
51 fn render_latex_snippet(&self) -> String {
52 let mut result = String::new();
53 result.push_str(&format!(
54 indoc! {r#"
55 \item \textbf{{{}}} \hfill \textit{{{}}} \\
56 "#},
57 self.title, format_date_range(&self.dates)
58 ));
59 if !self.description.is_empty() {
60 result.push_str(r#"\begin{itemize}[leftmargin=*, label=-]"#);
61 for desc in &self.description {
62 result.push_str(&format!(" \\item {}\n", desc));
63 }
64 result.push_str(r#"\end{itemize}"#);
65 }
66 result
67 }
68}
69
70impl ResumeProject {
71
72 pub fn builder() -> ResumeProjectBuilder {
73 ResumeProjectBuilder::default()
74 }
75
76 pub fn new(title: String, dates: DateRange, description: Vec<String>) -> Self {
77 Self { title, dates, description }
78 }
79
80 pub fn title(&self) -> &str {
81 &self.title
82 }
83
84 pub fn dates(&self) -> &DateRange {
85 &self.dates
86 }
87
88 pub fn description(&self) -> &[String] {
89 &self.description
90 }
91}
92
93#[derive(Default)]
94pub struct ResumeProjectBuilder {
95 title: Option<String>,
96 dates: Option<DateRange>,
97 description: Vec<String>,
98}
99
100impl ResumeProjectBuilder {
101 pub fn title(mut self, title: String) -> Self {
102 self.title = Some(title);
103 self
104 }
105
106 pub fn dates(mut self, dates: DateRange) -> Self {
107 self.dates = Some(dates);
108 self
109 }
110
111 pub fn description(mut self, description: Vec<String>) -> Self {
112 self.description = description;
113 self
114 }
115
116 pub fn build(self) -> ResumeProject {
117 ResumeProject {
118 title: self.title.expect("Title is required"),
119 dates: self.dates.expect("Dates are required"),
120 description: self.description,
121 }
122 }
123}