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(
63 "attach",
64 |_lua,
65 this,
66 (content_type, data, opts): (
67 String,
68 mlua::String,
69 Option<SerdeWrappedValue<AttachmentOptions>>,
70 )| {
71 this.mutate(|builder| {
72 builder.attach(&content_type, &data.as_bytes(), opts.as_deref())?;
73 Ok(())
74 })
75 .map_err(any_err)
76 },
77 );
78 methods.add_method("attach_part", |_lua, this, part: UserDataRef<PartRef>| {
79 let part = part.resolve().map_err(any_err)?.to_owned();
80 this.mutate(|builder| {
81 builder.attach_part(part);
82 Ok(())
83 })
84 .map_err(any_err)
85 });
86 methods.add_method("build", |_lua, this, ()| {
87 let part = this.take().map_err(any_err)?.build().map_err(any_err)?;
88 Ok(PartRef::new(part))
89 });
90 }
91}