use super::media::MediaData;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct DocumentData {
pub base64_data: String,
pub mime_type: String,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_url: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_count: Option<u32>,
}
impl MediaData for DocumentData {
fn base64_data(&self) -> &str {
&self.base64_data
}
fn mime_type(&self) -> String {
self.mime_type.clone()
}
fn is_url(&self) -> bool {
self.is_url
}
fn from_base64(base64_data: impl Into<String>, mime_type: impl Into<String>) -> Self {
Self {
base64_data: base64_data.into(),
mime_type: mime_type.into(),
is_url: false,
filename: None,
page_count: None,
}
}
fn guess_format(path: &Path) -> Option<String> {
match path.extension().and_then(|e| e.to_str()) {
Some(ext) if ext.eq_ignore_ascii_case("pdf") => Some("application/pdf".to_string()),
_ => None,
}
}
}
crate::impl_media_forwarders!(DocumentData, mime_type);
impl DocumentData {
pub fn from_url(url: impl Into<String>) -> Self {
Self {
base64_data: url.into(),
mime_type: String::new(),
is_url: true,
filename: None,
page_count: None,
}
}
pub fn with_filename(mut self, filename: impl Into<String>) -> Self {
self.filename = Some(filename.into());
self
}
pub fn with_page_count(mut self, page_count: u32) -> Self {
self.page_count = Some(page_count);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_pdf_extension_maps_to_the_pdf_mime_and_others_fail_loudly() {
assert_eq!(
DocumentData::guess_format(Path::new("report.pdf")).as_deref(),
Some("application/pdf")
);
assert_eq!(
DocumentData::guess_format(Path::new("REPORT.PDF")).as_deref(),
Some("application/pdf")
);
assert!(DocumentData::guess_format(Path::new("notes.docx")).is_none());
assert!(DocumentData::guess_format(Path::new("noext")).is_none());
}
#[test]
fn inline_bytes_round_trip_and_url_reference_stays_verbatim() {
let doc = DocumentData::from_bytes(b"%PDF-1.7", "application/pdf");
assert!(!doc.is_url());
assert_eq!(doc.to_bytes().unwrap(), b"%PDF-1.7");
assert!(doc
.to_data_url()
.starts_with("data:application/pdf;base64,"));
let url = DocumentData::from_url("https://example.com/paper.pdf");
assert!(url.is_url());
assert_eq!(url.to_data_url(), "https://example.com/paper.pdf");
}
}