Browse Source

Merge pull request #6 from bitzl/osc-array-type

Add OscArray type
add-osctime-alias-for-time-tags
Andreas Linz 1 year ago
committed by GitHub
parent
commit
59bc538f4d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 27 deletions
  1. +21
    -4
      src/decoder.rs
  2. +42
    -19
      src/encoder.rs
  3. +8
    -0
      src/types.rs
  4. +9
    -2
      tests/decoder_test.rs
  5. +12
    -2
      tests/encoder_test.rs

+ 21
- 4
src/decoder.rs View File

@ -1,6 +1,6 @@
use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use encoder;
use errors::OscError;
use types::{OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscType, Result};
use std::{io, char};
use std::io::{Read, BufRead};
@ -119,9 +119,26 @@ fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Resul
let type_tags: Vec<char> = raw_type_tags.chars().skip(1).collect();
let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
let mut stack: Vec<Vec<OscType>> = Vec::new();
for tag in type_tags {
let arg: OscType = read_osc_arg(cursor, tag)?;
args.push(arg);
if tag == '[' {
// array start: save current frame and start a new frame
// for the array's content
stack.push(args);
args = Vec::new();
} else if tag == ']' {
// found the end of the current array:
// create array object from current frame and step one level up
let array = OscType::Array(OscArray { content: args });
match stack.pop() {
Some(stashed) => args = stashed,
None => return Err(OscError::BadMessage("Encountered ] outside array")),
}
args.push(array);
} else {
let arg: OscType = read_osc_arg(cursor, tag)?;
args.push(arg);
}
}
Ok(args)
}

+ 42
- 19
src/encoder.rs View File

@ -1,7 +1,7 @@
use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use types::{OscBundle, OscMessage, OscPacket, OscType, Result};
use byteorder::{ByteOrder, BigEndian};
use byteorder::{BigEndian, ByteOrder};
/// Takes a reference to an OSC packet and returns
/// a byte vector on success. If the packet was invalid
@ -36,9 +36,9 @@ fn encode_message(msg: &OscMessage) -> Result> {
if let Some(ref args) = msg.args {
for arg in args {
let (bytes, tag): (Option<Vec<u8>>, char) = encode_arg(arg)?;
let (bytes, tags): (Option<Vec<u8>>, String) = encode_arg(arg)?;
type_tags.push(tag);
type_tags.extend(tags.chars());
if bytes.is_some() {
arg_bytes.extend(bytes.unwrap());
}
@ -91,34 +91,34 @@ fn encode_bundle(bundle: &OscBundle) -> Result> {
Ok(bundle_bytes)
}
fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, String)> {
match *arg {
OscType::Int(ref x) => {
let mut bytes = vec![0u8; 4];
BigEndian::write_i32(&mut bytes, *x);
Ok((Some(bytes), 'i'))
Ok((Some(bytes), "i".into()))
}
OscType::Long(ref x) => {
let mut bytes = vec![0u8; 8];
BigEndian::write_i64(&mut bytes, *x);
Ok((Some(bytes), 'h'))
Ok((Some(bytes), "h".into()))
}
OscType::Float(ref x) => {
let mut bytes = vec![0u8; 4];
BigEndian::write_f32(&mut bytes, *x);
Ok((Some(bytes), 'f'))
Ok((Some(bytes), "f".into()))
}
OscType::Double(ref x) => {
let mut bytes = vec![0u8; 8];
BigEndian::write_f64(&mut bytes, *x);
Ok((Some(bytes), 'd'))
Ok((Some(bytes), "d".into()))
}
OscType::Char(ref x) => {
let mut bytes = vec![0u8; 4];
BigEndian::write_u32(&mut bytes, *x as u32);
Ok((Some(bytes), 'c'))
Ok((Some(bytes), "c".into()))
}
OscType::String(ref x) => Ok((Some(encode_string(x.clone())), 's')),
OscType::String(ref x) => Ok((Some(encode_string(x.clone())), "s".into())),
OscType::Blob(ref x) => {
let padded_blob_length: usize = pad(x.len() as u64) as usize;
let mut bytes = vec![0u8; 4 + padded_blob_length];
@ -127,14 +127,38 @@ fn encode_arg(arg: &OscType) -> Result<(Option>, char)> {
for (i, v) in x.iter().enumerate() {
bytes[i + 4] = *v;
}
Ok((Some(bytes), 'b'))
Ok((Some(bytes), "b".into()))
}
OscType::Time(ref x, ref y) => Ok((Some(encode_time_tag(*x, *y)), "t".into())),
OscType::Midi(ref x) => Ok((Some(vec![x.port, x.status, x.data1, x.data2]), "m".into())),
OscType::Color(ref x) => Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), "r".into())),
OscType::Bool(ref x) => {
if *x {
Ok((None, "T".into()))
} else {
Ok((None, "F".into()))
}
}
OscType::Nil => Ok((None, "N".into())),
OscType::Inf => Ok((None, "I".into())),
OscType::Array(ref x) => {
let mut bytes = vec![0u8; 0];
let mut type_tags = String::from("[");
for v in x.content.iter() {
match encode_arg(v) {
Ok((Some(other_bytes), other_type_tags)) => {
bytes.extend(other_bytes);
type_tags.push_str(&other_type_tags);
}
Ok((None, other_type_tags)) => {
type_tags.push_str(&other_type_tags);
}
Err(err) => return Err(err),
}
}
type_tags.push_str("]");
Ok((Some(bytes), type_tags))
}
OscType::Time(ref x, ref y) => Ok((Some(encode_time_tag(*x, *y)), 't')),
OscType::Midi(ref x) => Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm')),
OscType::Color(ref x) => Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r')),
OscType::Bool(ref x) => if *x { Ok((None, 'T')) } else { Ok((None, 'F')) },
OscType::Nil => Ok((None, 'N')),
OscType::Inf => Ok((None, 'I')),
}
}
@ -172,7 +196,6 @@ pub fn pad(pos: u64) -> u64 {
}
}
fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
let mut bytes = vec![0u8; 8];
BigEndian::write_u32(&mut bytes[..4], sec);

+ 8
- 0
src/types.rs View File

@ -17,6 +17,7 @@ pub enum OscType {
Color(OscColor),
Midi(OscMidiMessage),
Bool(bool),
Array(OscArray),
Nil,
Inf,
}
@ -45,6 +46,7 @@ value_impl! {
(float, Float, f32),
(string, String, String),
(blob, Blob, Vec<u8>),
(array, Array, OscArray),
(long, Long, i64),
(double, Double, f64),
(char, Char, char),
@ -119,6 +121,12 @@ pub struct OscColor {
pub alpha: u8,
}
/// An OscArray color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscArray {
pub content: Vec<OscType>,
}
pub type Result<T> = result::Result<T, errors::OscError>;
impl From<String> for OscMessage {

+ 9
- 2
tests/decoder_test.rs View File

@ -4,7 +4,7 @@ extern crate rosc;
use byteorder::{BigEndian, ByteOrder};
use std::mem;
use rosc::{decoder, encoder};
use rosc::{decoder, encoder, OscType};
#[test]
fn test_decode_no_args() {
@ -58,7 +58,9 @@ fn test_decode_args() {
let c = '$';
let c_bytes: [u8; 4] = unsafe { mem::transmute((c as u32).to_be()) };
let type_tags = encoder::encode_string(",fdsTFibhNIc");
let a = vec![OscType::Int(i), OscType::Float(f), OscType::Int(i)];
let type_tags = encoder::encode_string(",fdsTFibhNIc[ifi]");
let args: Vec<u8> = f_bytes
.iter()
@ -70,6 +72,10 @@ fn test_decode_args() {
.chain(vec![0u8, 0u8].iter())
.chain(h_bytes.iter())
.chain(c_bytes.iter())
// array content
.chain(i_bytes.iter())
.chain(f_bytes.iter())
.chain(i_bytes.iter())
.map(|x| *x)
.collect::<Vec<u8>>();
@ -96,6 +102,7 @@ fn test_decode_args() {
rosc::OscType::Nil => (),
// test time-tags, midi-messages and chars
rosc::OscType::Char(x) => assert_eq!(c, x),
rosc::OscType::Array(x) => assert_eq!(a, x.content),
_ => panic!(),
}
}

+ 12
- 2
tests/encoder_test.rs View File

@ -1,7 +1,7 @@
extern crate rosc;
use rosc::{encoder, decoder};
use rosc::{OscMessage, OscMidiMessage, OscColor, OscPacket, OscType, OscBundle};
use rosc::{decoder, encoder};
use rosc::{OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscType};
#[test]
fn test_encode_message_wo_args() {
@ -55,6 +55,16 @@ fn test_encode_message_with_args() {
green: 192,
blue: 42,
alpha: 13,
}
.into(),
OscArray {
content: vec![
42i32.into(),
OscArray{
content: vec![1.23.into(), 3.21.into()]
}.into(),
"Yay".into()
]
}.into(),
]),
});

Loading…
Cancel
Save