1use crate::PartRef;
2use config::{SerdeWrappedValue, any_err};
3use mailparsing::{AttachmentOptions, MessageBuilder};
4use mlua::{UserData, UserDataMethods, UserDataRef};
5use parking_lot::Mutex;
6use std::sync::Arc;
7
8#[derive(Clone)]
9pub struct Builder {
10 builder: Arc<Mutex<Option<MessageBuilder<'static>>>>,
11}
12
13impl Builder {
14 pub fn new() -> Self {
15 Self {
16 builder: Arc::new(Mutex::new(Some(MessageBuilder::new()))),
17 }
18 }
19
20 pub fn mutate<F: FnOnce(&mut MessageBuilder) -> anyhow::Result<R>, R>(
21 &self,
22 f: F,
23 ) -> anyhow::Result<R> {
24 let mut builder = self.builder.lock();
25 match builder.as_mut() {
26 Some(builder) => (f)(builder),
27 None => anyhow::bail!("builder already built!"),
28 }
29 }
30
31 pub fn take(&self) -> anyhow::Result<MessageBuilder<'static>> {
32 match self.builder.lock().take() {
33 Some(builder) => Ok(builder),
34 None => anyhow::bail!("builder already built!"),
35 }
36 }
37}
38
39impl UserData for Builder {
40 fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
41 methods.add_method("set_stable_content", |_lua, this, stable: bool| {
42 this.mutate(|builder| {
43 builder.set_stable_content(stable);
44 Ok(())
45 })
46 .map_err(any_err)
47 });
48 methods.add_method("text_plain", |_lua, this, text: String| {
49 this.mutate(|builder| {
50 builder.text_plain(&text);
51 Ok(())
52 })
53 .map_err(any_err)
54 });
55 methods.add_method("text_html", |_lua, this, text: String| {
56 this.mutate(|builder| {
57 builder.text_html(&text);
58 Ok(())
59 })
60 .map_err(any_err)
61 });
62 methods.add_method("text_amp_html", |_lua, this, text: String| {
63 this.mutate(|builder| {
64 builder.text_amp_html(&text);
65 Ok(())
66 })
67 .map_err(any_err)
68 });
69 methods.add_method(
70 "attach",
71 |_lua,
72 this,
73 (content_type, data, opts): (
74 String,
75 mlua::String,
76 Option<SerdeWrappedValue<AttachmentOptions>>,
77 )| {
78 this.mutate(|builder| {
79 builder.attach(&content_type, &data.as_bytes(), opts.as_deref())?;
80 Ok(())
81 })
82 .map_err(any_err)
83 },
84 );
85 methods.add_method("attach_part", |_lua, this, part: UserDataRef<PartRef>| {
86 let part = part.resolve().map_err(any_err)?.to_owned();
87 this.mutate(|builder| {
88 builder.attach_part(part);
89 Ok(())
90 })
91 .map_err(any_err)
92 });
93 methods.add_method("build", |_lua, this, ()| {
94 let part = this.take().map_err(any_err)?.build().map_err(any_err)?;
95 Ok(PartRef::new(part))
96 });
97 }
98}