ableton-link-rs 0.1.1

Native Rust implementation of the Ableton Link protocol
Documentation
use std::{
    mem,
    ops::{Add, Neg, Sub},
};

use bincode::Decode;

pub const BEATS_SIZE: u32 = mem::size_of::<i64>() as u32;

#[derive(PartialEq, Eq, Copy, Clone, Default, PartialOrd, Ord, Decode, Debug)]
pub struct Beats {
    pub value: i64,
}

impl bincode::Encode for Beats {
    fn encode<E: bincode::enc::Encoder>(
        &self,
        encoder: &mut E,
    ) -> std::result::Result<(), bincode::error::EncodeError> {
        bincode::Encode::encode(&self.micro_beats(), encoder)
    }
}

impl Beats {
    pub const SIZE: u32 = mem::size_of::<i64>() as u32;

    pub fn new(beats: f64) -> Self {
        Self {
            value: (beats * 1e6).round() as i64,
        }
    }

    pub fn from_microbeats(micro_beats: i64) -> Self {
        Self { value: micro_beats }
    }

    pub fn micro_beats(self) -> i64 {
        self.value
    }

    pub fn abs(self) -> Self {
        Self {
            value: self.value.abs(),
        }
    }

    pub fn r#mod(self, rhs: Beats) -> Self {
        Self {
            value: self.value % rhs.value,
        }
    }

    pub fn floating(self) -> f64 {
        self.value as f64 / 1e6
    }
}

impl From<Beats> for f64 {
    fn from(beats: Beats) -> Self {
        beats.value as f64 / 1e6
    }
}

impl Neg for Beats {
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self { value: -self.value }
    }
}

impl Add for Beats {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value + rhs.value,
        }
    }
}

impl Sub for Beats {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value - rhs.value,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn from_floating() {
        let beats = Beats::new(0.5);
        assert_eq!(beats.micro_beats(), 500000);
        assert!((0.5 - beats.floating()).abs() < 1e-10);
    }

    #[test]
    fn from_micros() {
        let beats = Beats::from_microbeats(100000);
        assert_eq!(beats.micro_beats(), 100000);
        assert!((0.1 - beats.floating()).abs() < 1e-10);
    }

    #[test]
    fn size_bytes() {
        assert_eq!(BEATS_SIZE, 8);
    }
}