Skip to main content

use_bitrate/
lib.rs

1#![forbid(unsafe_code)]
2//! Primitive bitrate helpers.
3//!
4//! These helpers perform small size and duration calculations for media
5//! metadata.
6//!
7//! # Examples
8//!
9//! ```rust
10//! use use_bitrate::{Bitrate, bitrate_from_size, bytes_for_duration};
11//!
12//! let bitrate = Bitrate::new(8_000_000).unwrap();
13//!
14//! assert_eq!(bytes_for_duration(8_000_000, 10.0).unwrap(), 10_000_000);
15//! assert_eq!(bitrate_from_size(10_000_000, 10.0).unwrap(), 8_000_000);
16//! assert_eq!(bitrate.bits_per_second(), 8_000_000);
17//! ```
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct Bitrate {
21    bits_per_second: u64,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum BitrateError {
26    InvalidBitrate,
27    InvalidDuration,
28}
29
30fn validate_bitrate(bits_per_second: u64) -> Result<u64, BitrateError> {
31    if bits_per_second == 0 {
32        Err(BitrateError::InvalidBitrate)
33    } else {
34        Ok(bits_per_second)
35    }
36}
37
38fn validate_duration(duration_seconds: f64) -> Result<f64, BitrateError> {
39    if !duration_seconds.is_finite() || duration_seconds <= 0.0 {
40        Err(BitrateError::InvalidDuration)
41    } else {
42        Ok(duration_seconds)
43    }
44}
45
46impl Bitrate {
47    pub fn new(bits_per_second: u64) -> Result<Self, BitrateError> {
48        Ok(Self {
49            bits_per_second: validate_bitrate(bits_per_second)?,
50        })
51    }
52
53    #[must_use]
54    pub fn bits_per_second(&self) -> u64 {
55        self.bits_per_second
56    }
57
58    #[must_use]
59    pub fn kilobits_per_second(&self) -> f64 {
60        kilobits_per_second(self.bits_per_second)
61    }
62
63    #[must_use]
64    pub fn megabits_per_second(&self) -> f64 {
65        megabits_per_second(self.bits_per_second)
66    }
67}
68
69pub fn bits_for_duration(bits_per_second: u64, duration_seconds: f64) -> Result<u64, BitrateError> {
70    let bits_per_second = validate_bitrate(bits_per_second)?;
71    let duration_seconds = validate_duration(duration_seconds)?;
72    Ok((bits_per_second as f64 * duration_seconds).round() as u64)
73}
74
75pub fn bytes_for_duration(
76    bits_per_second: u64,
77    duration_seconds: f64,
78) -> Result<u64, BitrateError> {
79    let bits_per_second = validate_bitrate(bits_per_second)?;
80    let duration_seconds = validate_duration(duration_seconds)?;
81    Ok(((bits_per_second as f64 * duration_seconds) / 8.0).round() as u64)
82}
83
84pub fn bitrate_from_size(size_bytes: u64, duration_seconds: f64) -> Result<u64, BitrateError> {
85    let duration_seconds = validate_duration(duration_seconds)?;
86    Ok(((size_bytes as f64 * 8.0) / duration_seconds).round() as u64)
87}
88
89#[must_use]
90pub fn kilobits_per_second(bits_per_second: u64) -> f64 {
91    bits_per_second as f64 / 1_000.0
92}
93
94#[must_use]
95pub fn megabits_per_second(bits_per_second: u64) -> f64 {
96    bits_per_second as f64 / 1_000_000.0
97}
98
99#[cfg(test)]
100mod tests {
101    use super::{
102        Bitrate, BitrateError, bitrate_from_size, bits_for_duration, bytes_for_duration,
103        kilobits_per_second, megabits_per_second,
104    };
105
106    #[test]
107    fn computes_bitrate_size_helpers() {
108        let bitrate = Bitrate::new(8_000_000).unwrap();
109
110        assert_eq!(bitrate.bits_per_second(), 8_000_000);
111        assert_eq!(bits_for_duration(8_000_000, 10.0).unwrap(), 80_000_000);
112        assert_eq!(bytes_for_duration(8_000_000, 10.0).unwrap(), 10_000_000);
113        assert_eq!(bitrate_from_size(10_000_000, 10.0).unwrap(), 8_000_000);
114        assert_eq!(kilobits_per_second(8_000_000), 8_000.0);
115        assert_eq!(megabits_per_second(8_000_000), 8.0);
116        assert_eq!(bitrate.kilobits_per_second(), 8_000.0);
117        assert_eq!(bitrate.megabits_per_second(), 8.0);
118    }
119
120    #[test]
121    fn rejects_invalid_bitrate_inputs() {
122        assert_eq!(Bitrate::new(0), Err(BitrateError::InvalidBitrate));
123        assert_eq!(
124            bits_for_duration(0, 10.0),
125            Err(BitrateError::InvalidBitrate)
126        );
127        assert_eq!(
128            bytes_for_duration(8_000_000, 0.0),
129            Err(BitrateError::InvalidDuration)
130        );
131        assert_eq!(
132            bitrate_from_size(10_000_000, f64::NAN),
133            Err(BitrateError::InvalidDuration)
134        );
135    }
136}