xmltv 2.1.1

XMLTV for electronic program guide (EPG) parser and generator using serde.
Documentation
//! Programme length and time unit types.
use serde::{Deserialize, Serialize};

/// The true running length of a programme (excluding ads/trailers).
///
/// ```dtd
/// <!ELEMENT length (#PCDATA)>
/// <!ATTLIST length units (seconds | minutes | hours) #REQUIRED>
/// ```
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Length {
    #[serde(rename = "$text")]
    pub length: u32,
    #[serde(rename = "@units")]
    pub units: Units,
}

impl Length {
    /// Convert the length to whole seconds, truncating any remainder.
    pub fn to_seconds(&self) -> u32 {
        match self.units {
            Units::Seconds => self.length,
            Units::Minutes => self.length * 60,
            Units::Hours => self.length * 3600,
        }
    }

    /// Convert the length to whole minutes, truncating any remainder.
    pub fn to_minutes(&self) -> u32 {
        match self.units {
            Units::Seconds => self.length / 60,
            Units::Minutes => self.length,
            Units::Hours => self.length * 60,
        }
    }

    /// Decompose the length into `(hours, minutes, seconds)`.
    /// Hours are capped at `u8::MAX` (255) for extreme values.
    pub fn to_hms(&self) -> (u8, u8, u8) {
        let (h, m, s) = match self.units {
            Units::Seconds => {
                let (m, s) = divmod(self.length, 60);
                let (h, m) = divmod(m, 60);
                (h, m, s)
            }
            Units::Minutes => {
                let (h, m) = divmod(self.length, 60);
                (h, m, 0)
            }
            Units::Hours => (self.length, 0, 0),
        };
        (h.min(u32::from(u8::MAX)) as u8, m as u8, s as u8)
    }
}

/// Unit of time for a [`Length`] value.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[repr(u8)]
pub enum Units {
    Seconds,
    Minutes,
    Hours,
}

impl std::fmt::Display for Units {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Units::Seconds => f.write_str("seconds"),
            Units::Minutes => f.write_str("minutes"),
            Units::Hours => f.write_str("hours"),
        }
    }
}

/// Integer division returning `(quotient, remainder)`.
fn divmod(x: u32, y: u32) -> (u32, u32) {
    (x / y, x % y)
}