use crate::osc::write_osc_string;
use byteorder::{BigEndian, ByteOrder};
use std::fmt;
use std::fmt::Display;
use std::io::{Error, ErrorKind, Read};
static TYPE_TAG: &'static str = ",i";
pub static ADDR_A: &'static str = "/osm/a/tr";
pub static ADDR_B: &'static str = "/osm/b/tr";
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TriggerAddress {
A,
B,
}
impl Display for TriggerAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
&TriggerAddress::A => ADDR_A.to_string(),
&TriggerAddress::B => ADDR_B.to_string(),
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TriggerMessage {
addr: TriggerAddress,
arg: i32,
}
impl TriggerMessage {
pub fn new(addr: TriggerAddress, arg: i32) -> TriggerMessage {
return TriggerMessage {
addr: addr,
arg: arg,
};
}
pub fn to_vec(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
write_osc_string(&mut buf, self.addr.to_string());
write_osc_string(&mut buf, TYPE_TAG.to_string());
let mut be_bytes = [0; 4];
BigEndian::write_i32(&mut be_bytes, self.arg);
for byte in be_bytes.iter() {
buf.push(*byte);
}
return buf;
}
}
impl Display for TriggerMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {}))", self.addr, self.arg)
}
}
impl Read for TriggerMessage {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
let v = self.to_vec();
if buf.len() < v.len() {
let e = Error::new(ErrorKind::Other, "supplied buffer too small");
return Err(e);
}
buf[..v.len()].clone_from_slice(&v);
Ok(v.len())
}
}
#[cfg(test)]
mod tests {
use super::*;
const ADDR_START: usize = 0;
const ADDR_END: usize = 9;
const TAG_START: usize = 12;
const TAG_END: usize = 14;
const ARG_START: usize = 16;
const ARG_END: usize = 20;
const ARG_SIZE: usize = 4;
const MSG_LEN: usize = 20;
#[test]
fn test_trigger_addr() -> Result<(), failure::Error> {
let test_fixture_a = "/osm/a/tr";
let test_fixture_b = "/osm/a/tr";
let addr_a = TriggerAddress::A;
assert!(addr_a.to_string() == test_fixture_a);
let addr_b = TriggerAddress::B;
assert!(addr_a.to_string() == test_fixture_b);
assert!(addr_a != addr_b);
let addr_a2 = addr_a.clone();
assert!(addr_a == addr_a2);
Ok(())
}
#[test]
fn test_trigger_msg_new() -> Result<(), failure::Error> {
let test_val = 1;
let msg = TriggerMessage::new(TriggerAddress::A, test_val);
println!("{}", msg);
Ok(())
}
#[test]
fn test_trigger_message_to_vec() -> Result<(), failure::Error> {
let test_val = 1;
let msg = TriggerMessage::new(TriggerAddress::A, test_val);
let bytes = msg.to_vec();
let comp_bytes = ADDR_A.as_bytes();
let addr_bytes = &bytes[ADDR_START..ADDR_END];
assert!(comp_bytes == addr_bytes);
let comp_bytes = TYPE_TAG.as_bytes();
let flag_bytes = &bytes[TAG_START..TAG_END];
assert!(comp_bytes == flag_bytes);
let mut comp_bytes = [0; ARG_SIZE];
BigEndian::write_i32(&mut comp_bytes, test_val);
let arg_bytes = &bytes[ARG_START..ARG_END];
assert!(comp_bytes == arg_bytes);
Ok(())
}
#[test]
fn test_trigger_message_read() -> Result<(), failure::Error> {
let test_val = 0;
let mut bytes: [u8; 1024] = [0; 1024];
let mut msg = TriggerMessage::new(TriggerAddress::B, test_val);
let n = msg.read(&mut bytes).unwrap();
assert!(bytes[..n].len() == MSG_LEN);
let comp_bytes = ADDR_B.as_bytes();
let addr_bytes = &bytes[ADDR_START..ADDR_END];
assert!(comp_bytes == addr_bytes);
let comp_bytes = TYPE_TAG.as_bytes();
let flag_bytes = &bytes[TAG_START..TAG_END];
assert!(comp_bytes == flag_bytes);
let mut comp_bytes = [0; ARG_SIZE];
BigEndian::write_i32(&mut comp_bytes, test_val);
let arg_bytes = &bytes[ARG_START..ARG_END];
assert!(comp_bytes == arg_bytes);
Ok(())
}
}