use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutputMode {
Png,
Webp,
Mp4,
Webm,
Svg,
Css,
}
impl OutputMode {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, String> {
let path = path.as_ref();
let ext = path
.extension()
.and_then(|e| e.to_str())
.ok_or_else(|| {
format!(
"output path {} has no extension; expected one of png, webp, mp4, webm, svg, css",
path.display()
)
})?
.to_ascii_lowercase();
match ext.as_str() {
"png" => Ok(OutputMode::Png),
"webp" => Ok(OutputMode::Webp),
"mp4" => Ok(OutputMode::Mp4),
"webm" => Ok(OutputMode::Webm),
"svg" => Ok(OutputMode::Svg),
"css" => Ok(OutputMode::Css),
other => Err(format!(
"unsupported output extension {other}; expected one of png, webp, mp4, webm, svg, css"
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn png_lowercase() {
assert_eq!(OutputMode::from_path("a.png"), Ok(OutputMode::Png));
}
#[test]
fn png_uppercase() {
assert_eq!(OutputMode::from_path("a.PNG"), Ok(OutputMode::Png));
}
#[test]
fn webp() {
assert_eq!(OutputMode::from_path("a.webp"), Ok(OutputMode::Webp));
}
#[test]
fn mp4() {
assert_eq!(OutputMode::from_path("a.mp4"), Ok(OutputMode::Mp4));
}
#[test]
fn webm() {
assert_eq!(OutputMode::from_path("a.webm"), Ok(OutputMode::Webm));
}
#[test]
fn svg() {
assert_eq!(OutputMode::from_path("a.svg"), Ok(OutputMode::Svg));
}
#[test]
fn css() {
assert_eq!(OutputMode::from_path("a.css"), Ok(OutputMode::Css));
}
#[test]
fn unsupported_extension() {
let err = OutputMode::from_path("a.gif").unwrap_err();
assert!(
err.contains("gif"),
"error should mention the bad ext: {err}"
);
}
#[test]
fn missing_extension() {
let err = OutputMode::from_path("noext").unwrap_err();
assert!(err.contains("no extension"), "got: {err}");
}
#[test]
fn nested_path_uppercase_mp4() {
assert_eq!(
OutputMode::from_path("dir/sub/clip.MP4"),
Ok(OutputMode::Mp4)
);
}
#[test]
fn nested_path_no_extension() {
let err = OutputMode::from_path("dir/sub/clip").unwrap_err();
assert!(err.contains("no extension"), "got: {err}");
}
#[test]
fn trailing_dot() {
let err = OutputMode::from_path("foo.").unwrap_err();
assert!(err.contains("unsupported"), "got: {err}");
}
#[test]
fn multi_dot_unsupported_extension() {
let err = OutputMode::from_path("foo.PNG.bak").unwrap_err();
assert!(err.contains("bak"), "error should mention bak: {err}");
}
}