1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
//! This crate defines some utilities for dealing with [Open Sound Control] \(OSC\) //! messages. It is intended to be paired with [osc_address_derive] and provides //! a layer of abstraction over [serde_osc], //! but usage of either is optional and serialization/deserialization works //! with any serde backend. //! //! The primary feature of this crate is its [`OscMessage`] trait, which provides //! a **type-safe** way of encoding an OSC address and its payload while //! serializing/deserializating as if it were a generic //! `(osc_address: String, msg_payload: (...))` type suitable for [serde_osc]. //! //! The `OscMessage` trait is intended to be implemented automatically via a //! `#[derive(OscMessage)]` directive, by use of [osc_address_derive]. Because //! of this, that crate hosts usage examples, whereas this crate hosts only the //! API documentation. //! //! //! [Open Sound Control]: http://opensoundcontrol.org/spec-1_0 //! [osc_address_derive]: https://crates.io/crates/osc_address_derive //! [serde_osc]: https://crates.io/crates/serde_osc //! [`OscMessage`]: trait.OscMessage.html #![feature(try_from)] #[macro_use] extern crate serde_derive; extern crate serde; use std::convert::TryInto; use std::time::{UNIX_EPOCH, Duration, SystemTime}; /// OSC uses ntp time (epoch of 1900), and std::time uses Unix epoch (1970). /// This constant is used in conversion between the two formats. /// There are 70 years between 1900 and 1970; 17 of them are leap years. /// Leap seconds do not need to be considered, as they were introduced in 1972. const DELTA_1970_1900: u32 = (70*365 + 17)*86400; /// Type that exposes an OSC address and a message payload. Can be deserialized /// and serialized as if it were a `(String, ([payload_arguments, ...]))` sequence. /// /// The functions exposed by this trait can generally be ignored by the /// programmer. They primarily facilitate implementing Serde /// serialization/deserialization in an ergonomic fashion. pub trait OscMessage<'m> : serde::Serialize + serde::Deserialize<'m> { /// Append the address that this message would be sent to into the given string. /// This is intended to be used as a builder method called by `get_address`. /// Generally, users should not directly call this function. fn build_address(&self, string: &mut String); /// Determine the address that this message would be sent to, as a String. /// If this type is a struct (i.e. it represents just the payload of a message), /// then this method returns an empty string. /// In all other cases, it will return a string beginning with "/". fn get_address(&self) -> String { let mut s = String::new(); self.build_address(&mut s); s } /// Serialize the payload of this message, and not its address. /// In the case that the variants of this message are also enumerated OscMessages, /// this method should recurse and serialize the final (i.e. leaf) message payload. fn serialize_body<S: serde::ser::SerializeTuple>(&self, serializer: &mut S) -> Result<(), S::Error>; /// If `seq` represents the payload of an OSC message (i.e. the argument list), /// then this method deserializes the address + data into the appropriate enum /// variant. /// /// In the case that Self is a struct and represents the payload of a message /// (without any address), then it is expected that address is either "" or "/". fn deserialize_body<D: serde::de::SeqAccess<'m>>(address: String, seq: D) -> Result<Self, D::Error>; } /// An OSC bundle consists of 0 or more OSC packets that are to be handled /// atomically. Each packet is itself a message or another bundle. The bundle /// also contains a time tag indicating when it should be handled. #[derive(Debug)] #[derive(Serialize, Deserialize)] pub struct OscBundle<M> { time_tag: (u32, u32), messages: Vec<OscPacket<M>>, } #[derive(Debug)] #[derive(Serialize, Deserialize)] #[serde(untagged)] /// An OSC packet represents either a single OSC message, or a bundle with an /// associated time of zero or more OSC packets. pub enum OscPacket<M> { Message(M), Bundle(OscBundle<M>), } /// Time tag assigned to each [`OscBundle`](struct.OscBundle.html). #[derive(Copy, Clone, Debug)] pub enum OscTime { /// Indication to execute the bundle contents immediately upon receipt. Now, /// Execute the bundle contents at a specified time. At(AbsOscTime), } #[derive(Copy, Clone, Debug)] /// OSC uses ntp time, i.e. absolute # of seconds since 1970 + a fraction of a second. pub struct AbsOscTime { sec: u32, frac: u32, } impl<M> OscBundle<M> { /// Return the time at which this OSC bundle should be handled. pub fn time_tag(&self) -> OscTime { OscTime::new(self.time_tag.0, self.time_tag.1) } /// Access all messages contained in the bundle. pub fn messages(&self) -> &Vec<OscPacket<M>> { &self.messages } } impl OscTime { /// Create a OSC time from seconds and a fraction of a second. /// In the special case that `sec == 0` and `frac == 1`, this is to be interpreted /// as "now" or "immediately upon the time of message receipt." pub fn new(sec: u32, frac: u32) -> Self { match (sec, frac) { (0, 1) => OscTime::Now, _ => OscTime::At(AbsOscTime::new(sec, frac)), } } /// Convert the OSC time tag into a type from the std::time library. /// If `self == OscTime::now`, it will return the current system time. /// Note that this can fail to unrepresentable times, in which case None /// is returned. /// /// See [AbsOscTime::as_system_time] for more details. /// [AbsOscTime::as_system_time]: struct.AbsOscTime.html#method.as_system_time pub fn as_system_time(&self) -> Option<SystemTime> { match *self { OscTime::At(ref abs_time) => abs_time.as_system_time(), OscTime::Now => Some(SystemTime::now()), } } } impl AbsOscTime { /// Create a OSC time from seconds and a fraction of a second. /// It is assumed that `(sec, frac) != (0, 1)` -- otherwise the time should /// be represented as `OscTime::Now`. pub fn new(sec: u32, frac: u32) -> Self { Self{ sec, frac } } /// `std::time::SystemTime` -> `AbsOscTime`. /// Note that the OSC time can only represent dates out to year 2036, /// but `SystemTime` allows greater range. Hence, this returns `None` if the /// time is not representable. pub fn from_system_time(t: SystemTime) -> Option<Self> { let since_epoch = t.duration_since(UNIX_EPOCH); // Unwrap errors; transform them to None. let since_epoch = match since_epoch { Err(_) => return None, Ok(dur) => dur, }; let unix_secs: Result<u32, _> = since_epoch.as_secs().try_into(); // Unwrap errors; transform them to None. let unix_secs = match unix_secs { Err(_) => return None, Ok(secs) => secs, }; let ntp_secs = unix_secs.checked_add(DELTA_1970_1900); ntp_secs.map(|ntp_secs| { // NOTE: will never overflow; casting u32 to u64 and multiplying by 2**32 is safe; // Duration::subsec_nanos() is guaranteed to be < 10^9, so dividing the result // by 10^9 gives a value < 2**32 .'. casting to u32 is safe. let frac = ((since_epoch.subsec_nanos() as u64) << 32) / 1000000000; Self::new(ntp_secs, frac as u32) }) } /// Number of seconds since Jan 1, 1900. pub fn sec(&self) -> u32 { self.sec } /// Number of `1/2^32`th fractional seconds to be added with the `sec()` field. /// e.g. `1000` represents `1000/2^32` seconds. pub fn frac(&self) -> u32 { self.frac } /// The number of whole seconds and fractional seconds, as a tuple. pub fn sec_frac(&self) -> (u32, u32) { (self.sec, self.frac) } /// Convert the OSC time tag into a type from the `std::time` library. /// This may fail because `std::time` only allows times >= unix epoch (1970), /// whereas OSC allows times >= 1900. /// Upon such failure, `None` is returned. pub fn as_system_time(&self) -> Option<SystemTime> { // Converting ntp time to unix time, described here: http://stackoverflow.com/a/29138806/216292 let secs_unix = self.sec().checked_sub(DELTA_1970_1900); secs_unix.map(|secs_unix| { // u32 frac to nanos is (frac / 2^32) * 10^9, // NOTE: will never overflow; a u32 * 10*9 can always fit inside a u64, // and a u64 >> 32 always fits in a u32. let nanos = (self.frac() as u64 * 1000000000) >> 32; UNIX_EPOCH + Duration::new(secs_unix as u64, nanos as u32) }) } }