1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
7
8pub const ISO_EXTENSION: &str = "iso";
10pub const IMAGE_EXTENSION: &str = "img";
12pub const ISO_EXTENSIONS: &[&str] = &["iso", "img"];
14
15#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
17pub enum IsoFormat {
18 Iso9660,
20 Udf,
22 Hybrid,
24 #[default]
26 Unknown,
27}
28
29impl IsoFormat {
30 #[must_use]
32 pub const fn as_str(self) -> &'static str {
33 match self {
34 Self::Iso9660 => "iso9660",
35 Self::Udf => "udf",
36 Self::Hybrid => "hybrid",
37 Self::Unknown => "unknown",
38 }
39 }
40}
41
42impl fmt::Display for IsoFormat {
43 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44 formatter.write_str(self.as_str())
45 }
46}
47
48#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
50pub enum IsoVolumeKind {
51 Bootable,
53 Data,
55 Audio,
57 Hybrid,
59 #[default]
61 Unknown,
62}
63
64impl IsoVolumeKind {
65 #[must_use]
67 pub const fn as_str(self) -> &'static str {
68 match self {
69 Self::Bootable => "bootable",
70 Self::Data => "data",
71 Self::Audio => "audio",
72 Self::Hybrid => "hybrid",
73 Self::Unknown => "unknown",
74 }
75 }
76}
77
78impl fmt::Display for IsoVolumeKind {
79 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
80 formatter.write_str(self.as_str())
81 }
82}
83
84#[must_use]
86pub fn is_iso_extension(extension: &str) -> bool {
87 matches!(normalize_extension(extension).as_str(), "iso" | "img")
88}
89
90#[must_use]
92pub fn is_iso_filename(name: &str) -> bool {
93 let parts = filename_parts(name);
94
95 matches!(parts.as_slice(), [.., last] if matches!(last.as_str(), "iso" | "img"))
96}
97
98fn normalize_extension(extension: &str) -> String {
99 extension
100 .trim()
101 .trim_start_matches('.')
102 .to_ascii_lowercase()
103}
104
105fn filename_parts(name: &str) -> Vec<String> {
106 name.trim()
107 .to_ascii_lowercase()
108 .rsplit(['/', '\\'])
109 .next()
110 .unwrap_or_default()
111 .trim_start_matches('.')
112 .split('.')
113 .filter(|part| !part.is_empty())
114 .map(str::to_owned)
115 .collect()
116}
117
118#[cfg(test)]
119mod tests {
120 use super::{ISO_EXTENSIONS, IsoFormat, IsoVolumeKind, is_iso_extension, is_iso_filename};
121
122 #[test]
123 fn detects_iso_extensions() {
124 assert!(is_iso_extension(".iso"));
125 assert!(is_iso_extension("img"));
126 assert_eq!(ISO_EXTENSIONS[0], "iso");
127 }
128
129 #[test]
130 fn detects_iso_filenames() {
131 assert!(is_iso_filename("installer.iso"));
132 assert!(is_iso_filename("disk.IMG"));
133 assert!(!is_iso_filename("bundle.zip"));
134 }
135
136 #[test]
137 fn exposes_default_and_unknown_labels() {
138 assert_eq!(IsoFormat::default(), IsoFormat::Unknown);
139 assert_eq!(IsoFormat::Udf.as_str(), "udf");
140 assert_eq!(IsoVolumeKind::default(), IsoVolumeKind::Unknown);
141 assert_eq!(IsoVolumeKind::Audio.as_str(), "audio");
142 }
143}