use bitflags::bitflags;
use otspec::types::*;
use otspec::{
DeserializationError, Deserializer, ReaderContext, SerializationError, Serialize, Serializer,
};
use otspec_macros::{Deserialize, Serialize};
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct TupleIndexFlags: u16 {
const EMBEDDED_PEAK_TUPLE = 0x8000;
const INTERMEDIATE_REGION = 0x4000;
const PRIVATE_POINT_NUMBERS = 0x2000;
const TUPLE_INDEX_MASK = 0x0FFF;
}
}
#[allow(non_snake_case, non_camel_case_types)]
#[derive(Debug, PartialEq, Clone)]
pub struct TupleVariationHeader {
pub size: uint16,
pub flags: TupleIndexFlags,
pub sharedTupleIndex: uint16,
pub peakTuple: Option<Vec<f32>>,
pub startTuple: Option<Vec<f32>>,
pub endTuple: Option<Vec<f32>>,
}
impl TupleVariationHeader {
pub fn from_bytes(
c: &mut ReaderContext,
axis_count: uint16,
) -> Result<Self, DeserializationError> {
let mut res = TupleVariationHeader {
size: 0,
peakTuple: None,
startTuple: None,
endTuple: None,
flags: TupleIndexFlags::empty(),
sharedTupleIndex: 0,
};
res.size = c.de()?;
res.flags = c.de()?;
res.sharedTupleIndex = res.flags.bits() & TupleIndexFlags::TUPLE_INDEX_MASK.bits();
if res.flags.contains(TupleIndexFlags::EMBEDDED_PEAK_TUPLE) {
res.peakTuple = Some(
(c.de_counted(axis_count.into())? as Vec<i16>)
.iter()
.map(|x| F2DOT14::from_packed(*x).into())
.collect(),
);
}
if res.flags.contains(TupleIndexFlags::INTERMEDIATE_REGION) {
res.startTuple = Some(
(c.de_counted(axis_count.into())? as Vec<i16>)
.iter()
.map(|x| F2DOT14::from_packed(*x).into())
.collect(),
);
res.endTuple = Some(
(c.de_counted(axis_count.into())? as Vec<i16>)
.iter()
.map(|x| F2DOT14::from_packed(*x).into())
.collect(),
);
}
Ok(res)
}
}
impl Serialize for TupleVariationHeader {
fn to_bytes(&self, data: &mut Vec<u8>) -> Result<(), SerializationError> {
data.put(self.size)?;
data.put(self.sharedTupleIndex | self.flags.bits())?;
if self.flags.contains(TupleIndexFlags::EMBEDDED_PEAK_TUPLE) {
if self.peakTuple.is_some() {
for coord in self.peakTuple.as_ref().unwrap() {
F2DOT14::from(*coord).to_bytes(data)?;
}
} else {
panic!("EMBEDDED_PEAK_TUPLE was set, but there wasn't one.");
}
}
if self.flags.contains(TupleIndexFlags::INTERMEDIATE_REGION) {
if self.startTuple.is_some() {
for coord in self.startTuple.as_ref().unwrap() {
F2DOT14::from(*coord).to_bytes(data)?;
}
} else {
panic!("INTERMEDIATE_REGION was set, but there was no start tuple.");
}
if self.endTuple.is_some() {
for coord in self.endTuple.as_ref().unwrap() {
F2DOT14::from(*coord).to_bytes(data)?;
}
} else {
panic!("INTERMEDIATE_REGION was set, but there was no end tuple.");
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::otvar::{TupleIndexFlags, TupleVariationHeader};
use otspec::ReaderContext;
#[test]
fn test_tvh_serde() {
let tvh = TupleVariationHeader {
size: 33,
flags: TupleIndexFlags::EMBEDDED_PEAK_TUPLE,
sharedTupleIndex: 0,
peakTuple: Some(vec![0.5]),
startTuple: None,
endTuple: None,
};
let serialized = otspec::ser::to_bytes(&tvh).unwrap();
let deserialized =
TupleVariationHeader::from_bytes(&mut ReaderContext::new(serialized), 1).unwrap();
assert_eq!(deserialized, tvh);
}
#[test]
fn test_tvh_deser() {
let binary_tvh: Vec<u8> = vec![0, 33, 128, 0, 32, 0];
let deserialized =
TupleVariationHeader::from_bytes(&mut ReaderContext::new(binary_tvh.clone()), 1)
.unwrap();
let serialized = otspec::ser::to_bytes(&deserialized).unwrap();
assert_eq!(serialized, binary_tvh);
}
}