open_sound_control/
timetag.rs1use crate::helpers::OscParseError;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4#[derive(Debug, PartialEq, Clone)]
16pub struct OscTimeTag {
17 pub seconds: u32, pub fractional: u32, }
20
21impl OscTimeTag {
22
23 pub fn now() -> Self {
25 let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time calculation error");
26
27 let unix_seconds = now.as_secs() as u64;
28 let unix_nanos = now.subsec_nanos() as u64;
29 let ntp_seconds = unix_seconds + 2208988800;
30 let fractional = ((unix_nanos as f64 / 1_000_000_000.0) * (u32::MAX as f64 + 1.0)) as u32;
31
32 OscTimeTag {
33 seconds: ntp_seconds as u32,
34 fractional,
35 }
36 }
37
38 pub fn to_bytes(&self) -> [u8; 8] {
40 let mut bytes = [0u8; 8];
41 bytes[..4].copy_from_slice(&self.seconds.to_be_bytes());
42 bytes[4..].copy_from_slice(&self.fractional.to_be_bytes());
43 bytes
44 }
45
46 pub fn from_i64(value: i64) -> Self {
48 let uvalue = value as u64; let seconds = (uvalue >> 32) as u32;
50 let fractional = uvalue as u32; Self { seconds, fractional }
52 }
53
54 pub fn from_bytes(bytes: &[u8]) -> Result<Self, OscParseError> {
56 if bytes.len() < 8 {
57 return Err(OscParseError::NotEnoughData);
58 }
59 let seconds = u32::from_be_bytes(bytes[..4].try_into().unwrap());
60 let fractional = u32::from_be_bytes(bytes[4..8].try_into().unwrap());
61 Ok(Self { seconds, fractional })
62 }
63}
64
65#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_time_tag() {
73 let tag = OscTimeTag { seconds: 0x11223344, fractional: 0x55667788 };
74 assert_eq!(tag.to_bytes(),[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
75
76 let result = OscTimeTag::from_bytes(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
77 assert!(result.is_ok());
78 let tag = result.unwrap();
79 assert_eq!(tag.seconds, 0x11223344);
80 assert_eq!(tag.fractional, 0x55667788);
81
82 let immediately_tag = OscTimeTag { seconds: 0, fractional: 1 };
83 assert_eq!(immediately_tag.seconds, 0);
84 assert_eq!(immediately_tag.fractional, 1);
85 }
86}