#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilmFormat {
IX240,
F135,
F135Half,
F16,
F645,
F66,
F67,
F68,
F69,
Custom(u32),
}
impl FilmFormat {
const fn height_tenths(self) -> u32 {
match self {
Self::IX240 => 302,
Self::F135 => 360,
Self::F135Half => 180,
Self::F16 => 200,
Self::F645 => 415,
Self::F66 => 560,
Self::F67 => 695,
Self::F68 => 760,
Self::F69 => 840,
Self::Custom(mm) => mm * 10,
}
}
pub const fn height_mm(self) -> u32 {
(self.height_tenths() + 5) / 10
}
pub fn height_dots(self, dpi: u16) -> u32 {
let num = u64::from(self.height_tenths()) * u64::from(dpi);
((num + 127) / 254) as u32
}
pub fn from_holder(holder_id: u8) -> Option<Self> {
match holder_id {
0x12 => Some(Self::F16), 0x19 => Some(Self::F645), 0x1A => Some(Self::F66), 0x1B => Some(Self::F67), 0x1C => Some(Self::F68), 0x1D => Some(Self::F69), _ => None,
}
}
pub fn choices_for_holder(holder_id: u8) -> Option<&'static [Self]> {
match holder_id {
0x14 => Some(&[Self::F66, Self::F67, Self::F69]), 0x15 => Some(&[Self::F66, Self::F67, Self::F69]), 0x16 => Some(&[Self::F66, Self::F67, Self::F69]), 0x17 => Some(&[Self::F66, Self::F67, Self::F69]), 0x18 => Some(&[Self::F66, Self::F67, Self::F69]), _ => None,
}
}
pub fn from_adapter(adapter_id: u8) -> Option<Self> {
match adapter_id {
0x31 => Some(Self::F135), 0x35 => Some(Self::IX240), 0x32 => Some(Self::F135), _ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_heights() {
assert_eq!(FilmFormat::F135.height_mm(), 36);
assert_eq!(FilmFormat::F16.height_mm(), 20);
assert_eq!(FilmFormat::F66.height_mm(), 56);
assert_eq!(FilmFormat::F69.height_mm(), 84);
assert_eq!(FilmFormat::Custom(100).height_mm(), 100);
}
#[test]
fn a_format_is_its_gate_rather_than_its_name() {
assert_eq!(FilmFormat::F645.height_tenths(), 415);
assert_eq!(FilmFormat::F67.height_tenths(), 695);
assert_eq!(FilmFormat::F68.height_tenths(), 760);
assert_eq!(
FilmFormat::F135Half.height_tenths() * 2,
FilmFormat::F135.height_tenths()
);
}
#[test]
fn dots_at_4000_dpi() {
assert_eq!(FilmFormat::F66.height_dots(4000), 8819);
assert_eq!(FilmFormat::F69.height_dots(4000), 13228);
assert_eq!(FilmFormat::F645.height_dots(4000), 6535);
}
#[test]
fn gr_holder_fixes_format() {
assert_eq!(FilmFormat::from_holder(0x1A), Some(FilmFormat::F66));
assert_eq!(FilmFormat::from_holder(0x1D), Some(FilmFormat::F69));
assert_eq!(FilmFormat::from_holder(0x17), None);
}
#[test]
fn strip_holder_offers_choices() {
let choices = FilmFormat::choices_for_holder(0x17).unwrap();
assert!(choices.contains(&FilmFormat::F66));
assert!(choices.contains(&FilmFormat::F69));
assert!(FilmFormat::choices_for_holder(0x1A).is_none());
}
}