email/email/message/template/
mod.rs1pub mod config;
7pub mod forward;
8pub mod new;
9pub mod reply;
10
11use std::{
12 borrow::Cow,
13 fmt,
14 ops::{Deref, DerefMut},
15};
16
17pub use mml::{
18 message::{FilterHeaders, FilterParts},
19 MimeInterpreter,
20};
21
22#[derive(Clone, Debug, Default, Eq, PartialEq)]
23#[cfg_attr(
24 feature = "derive",
25 derive(serde::Serialize, serde::Deserialize),
26 serde(rename_all = "kebab-case")
27)]
28pub struct Template {
29 pub content: String,
30 pub cursor: TemplateCursor,
31}
32
33impl Template {
34 pub fn new(content: impl ToString) -> Self {
35 Self::new_with_cursor(content, TemplateCursor::default())
36 }
37
38 pub fn new_with_cursor(content: impl ToString, cursor: impl Into<TemplateCursor>) -> Self {
39 let content = content.to_string();
40 let cursor = cursor.into();
41 Self { content, cursor }
42 }
43
44 pub fn append(&mut self, section: impl AsRef<str>) {
45 if !self.content.is_empty() {
46 self.content.push_str(section.as_ref())
47 }
48 }
49}
50
51impl Deref for Template {
52 type Target = String;
53
54 fn deref(&self) -> &Self::Target {
55 &self.content
56 }
57}
58
59impl DerefMut for Template {
60 fn deref_mut(&mut self) -> &mut Self::Target {
61 &mut self.content
62 }
63}
64
65impl From<String> for Template {
66 fn from(s: String) -> Self {
67 Self::new(s)
68 }
69}
70
71impl fmt::Display for Template {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "{}", self.content)
74 }
75}
76
77#[derive(Clone, Debug, Eq)]
78#[cfg_attr(
79 feature = "derive",
80 derive(serde::Serialize, serde::Deserialize),
81 serde(rename_all = "kebab-case")
82)]
83pub struct TemplateCursor {
84 pub row: usize,
85 pub col: usize,
86
87 #[cfg_attr(feature = "derive", serde(skip))]
88 locked: bool,
89}
90
91impl TemplateCursor {
92 pub fn new(row: usize, col: usize) -> Self {
93 Self {
94 row,
95 col,
96 locked: false,
97 }
98 }
99
100 pub fn lock(&mut self) {
101 self.locked = true;
102 }
103
104 pub fn is_locked(&self) -> bool {
105 self.locked
106 }
107}
108
109impl Default for TemplateCursor {
110 fn default() -> Self {
111 Self {
112 row: 1,
113 col: 0,
114 locked: false,
115 }
116 }
117}
118
119impl PartialEq for TemplateCursor {
120 fn eq(&self, other: &Self) -> bool {
121 self.row == other.row && self.col == other.col
122 }
123}
124
125impl From<(usize, usize)> for TemplateCursor {
126 fn from((row, col): (usize, usize)) -> Self {
127 TemplateCursor::new(row, col)
128 }
129}
130
131#[derive(Debug, Eq, PartialEq)]
132pub struct TemplateBody {
133 content: String,
134 buffer: String,
135 cursor: TemplateCursor,
136 push_new_lines: bool,
137}
138
139impl TemplateBody {
140 pub fn new(mut cursor: TemplateCursor) -> Self {
141 cursor.row += 1;
142
143 Self {
144 content: Default::default(),
145 buffer: Default::default(),
146 cursor,
147 push_new_lines: false,
148 }
149 }
150
151 pub fn flush(&mut self) {
152 let mut buffer = String::new();
153
154 if self.push_new_lines {
155 buffer.push_str("\n\n");
156 } else {
157 self.push_new_lines = true;
158 };
159
160 buffer.push_str(self.buffer.drain(..).as_str());
161
162 if !self.cursor.is_locked() {
163 match buffer.rsplit_once('\n') {
164 Some((left, right)) => {
165 let left_lines_count = left
168 .chars()
169 .fold(1, |count, c| count + if c == '\n' { 1 } else { 0 });
170
171 self.cursor.row += left_lines_count;
172 self.cursor.col = right.len();
173 }
174 None => {
175 self.cursor.col += buffer.len();
176 }
177 }
178 }
179
180 self.content.push_str(&buffer)
181 }
182}
183
184impl Deref for TemplateBody {
185 type Target = String;
186
187 fn deref(&self) -> &Self::Target {
188 &self.buffer
189 }
190}
191
192impl DerefMut for TemplateBody {
193 fn deref_mut(&mut self) -> &mut Self::Target {
194 &mut self.buffer
195 }
196}
197
198impl From<TemplateBody> for Cow<'_, str> {
199 fn from(value: TemplateBody) -> Self {
200 value.content.into()
201 }
202}