use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct InputFile {
pub path: PathBuf,
}
impl From<PathBuf> for InputFile {
fn from(path: PathBuf) -> Self {
Self { path }
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum FileUpload {
String(String),
InputFile(InputFile),
}
impl From<String> for FileUpload {
fn from(file: String) -> Self {
Self::String(file)
}
}
impl From<PathBuf> for FileUpload {
fn from(path: PathBuf) -> Self {
Self::InputFile(InputFile { path })
}
}
impl From<InputFile> for FileUpload {
fn from(file: InputFile) -> Self {
Self::InputFile(file)
}
}
#[cfg(feature = "trait-async")]
pub(crate) trait HasInputFile {
fn clone_path(&self) -> Option<PathBuf>;
fn replace_attach(&mut self, name: &str) -> Option<PathBuf>;
fn replace_attach_dyn(&mut self, index: impl FnOnce() -> usize) -> Option<(String, PathBuf)>;
}
#[cfg(feature = "trait-async")]
impl HasInputFile for FileUpload {
fn clone_path(&self) -> Option<PathBuf> {
match self {
Self::InputFile(input_file) => Some(input_file.path.clone()),
Self::String(_) => None,
}
}
fn replace_attach(&mut self, name: &str) -> Option<PathBuf> {
match self {
Self::InputFile(_) => {
let attach = Self::String(format!("attach://{name}"));
let Self::InputFile(file) = std::mem::replace(self, attach) else {
unreachable!("the match already ensures it being an input file");
};
Some(file.path)
}
Self::String(_) => None,
}
}
fn replace_attach_dyn(&mut self, index: impl FnOnce() -> usize) -> Option<(String, PathBuf)> {
match self {
Self::InputFile(_) => {
let name = format!("file{}", index());
let attach = Self::String(format!("attach://{name}"));
let Self::InputFile(file) = std::mem::replace(self, attach) else {
unreachable!("the match already ensures it being an input file");
};
Some((name, file.path))
}
Self::String(_) => None,
}
}
}
#[cfg(feature = "trait-async")]
impl HasInputFile for Option<FileUpload> {
fn clone_path(&self) -> Option<PathBuf> {
match self {
Some(FileUpload::InputFile(input_file)) => Some(input_file.path.clone()),
_ => None,
}
}
fn replace_attach(&mut self, name: &str) -> Option<PathBuf> {
match self {
Some(FileUpload::InputFile(_)) => {
let attach = Some(FileUpload::String(format!("attach://{name}")));
let Some(FileUpload::InputFile(file)) = std::mem::replace(self, attach) else {
unreachable!("the match already ensures it being an input file");
};
Some(file.path)
}
_ => None,
}
}
fn replace_attach_dyn(&mut self, index: impl FnOnce() -> usize) -> Option<(String, PathBuf)> {
match self {
Some(FileUpload::InputFile(_)) => {
let name = format!("file{}", index());
let attach = Some(FileUpload::String(format!("attach://{name}")));
let Some(FileUpload::InputFile(file)) = std::mem::replace(self, attach) else {
unreachable!("the match already ensures it being an input file");
};
Some((name, file.path))
}
_ => None,
}
}
}