use base64::{Engine as _, engine::general_purpose};
use std::path::PathBuf;
pub struct ImageAttachment {
pub base64_data: String,
pub temp_path: PathBuf,
pub size_bytes: usize,
pub format: String,
}
pub struct AttachmentState {
pub attachments: Vec<ImageAttachment>,
next_id: usize,
}
impl Default for AttachmentState {
fn default() -> Self {
Self {
attachments: Vec::new(),
next_id: 1,
}
}
}
impl AttachmentState {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, image_bytes: &[u8], format: String) -> usize {
let id = self.next_id;
self.next_id += 1;
let size_bytes = image_bytes.len();
let base64_data = general_purpose::STANDARD.encode(image_bytes);
let temp_path = std::env::temp_dir().join(format!("mermaid-img-{}.{}", id, format));
let _ = std::fs::write(&temp_path, image_bytes);
self.attachments.push(ImageAttachment {
base64_data,
temp_path,
size_bytes,
format,
});
id
}
pub fn remove_last(&mut self) -> bool {
if let Some(attachment) = self.attachments.pop() {
let _ = std::fs::remove_file(&attachment.temp_path);
true
} else {
false
}
}
pub fn remove_at(&mut self, index: usize) -> bool {
if index < self.attachments.len() {
let attachment = self.attachments.remove(index);
let _ = std::fs::remove_file(&attachment.temp_path);
true
} else {
false
}
}
pub fn clear(&mut self) {
for attachment in self.attachments.drain(..) {
let _ = std::fs::remove_file(&attachment.temp_path);
}
}
pub fn is_empty(&self) -> bool {
self.attachments.is_empty()
}
pub fn len(&self) -> usize {
self.attachments.len()
}
pub fn take_base64_data(&mut self) -> Option<Vec<String>> {
if self.attachments.is_empty() {
return None;
}
let data: Vec<String> = self
.attachments
.iter()
.map(|a| a.base64_data.clone())
.collect();
self.clear();
Some(data)
}
pub fn last_temp_path(&self) -> Option<&PathBuf> {
self.attachments.last().map(|a| &a.temp_path)
}
}
impl Drop for AttachmentState {
fn drop(&mut self) {
self.clear();
}
}