use crate::Result;
use std::io::{Read, Write};
#[derive(Debug, Default, PartialEq)]
pub struct Vlr {
pub reserved: u16,
pub user_id: [u8; 16],
pub record_id: u16,
pub record_length_after_header: RecordLength,
pub description: [u8; 32],
#[allow(missing_docs)]
pub data: Vec<u8>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RecordLength {
Vlr(u16),
Evlr(u64),
}
impl Vlr {
#[allow(clippy::field_reassign_with_default)]
pub fn read_from<R: Read>(mut read: R, extended: bool) -> Result<Vlr> {
use byteorder::{LittleEndian, ReadBytesExt};
let mut vlr = Vlr::default();
vlr.reserved = read.read_u16::<LittleEndian>()?;
read.read_exact(&mut vlr.user_id)?;
vlr.record_id = read.read_u16::<LittleEndian>()?;
vlr.record_length_after_header = if extended {
RecordLength::Evlr(read.read_u64::<LittleEndian>()?)
} else {
RecordLength::Vlr(read.read_u16::<LittleEndian>()?)
};
read.read_exact(&mut vlr.description)?;
vlr.data
.resize(usize::from(vlr.record_length_after_header), 0);
read.read_exact(&mut vlr.data)?;
Ok(vlr)
}
pub fn write_to<W: Write>(&self, mut write: W) -> Result<()> {
use byteorder::{LittleEndian, WriteBytesExt};
write.write_u16::<LittleEndian>(self.reserved)?;
write.write_all(&self.user_id)?;
write.write_u16::<LittleEndian>(self.record_id)?;
match self.record_length_after_header {
RecordLength::Vlr(n) => write.write_u16::<LittleEndian>(n)?,
RecordLength::Evlr(n) => write.write_u64::<LittleEndian>(n)?,
}
write.write_all(&self.description)?;
write.write_all(&self.data)?;
Ok(())
}
}
impl From<RecordLength> for u64 {
fn from(record_length: RecordLength) -> u64 {
match record_length {
RecordLength::Vlr(n) => u64::from(n),
RecordLength::Evlr(n) => n,
}
}
}
impl From<RecordLength> for usize {
fn from(record_length: RecordLength) -> usize {
u64::from(record_length) as usize
}
}
impl Default for RecordLength {
fn default() -> RecordLength {
RecordLength::Vlr(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn roundtrip() {
let vlr = Vlr::default();
let mut cursor = Cursor::new(Vec::new());
vlr.write_to(&mut cursor).unwrap();
cursor.set_position(0);
assert_eq!(vlr, Vlr::read_from(cursor, false).unwrap());
}
#[test]
fn roundtrip_evlr() {
let evlr = Vlr {
record_length_after_header: RecordLength::Evlr(0),
..Default::default()
};
let mut cursor = Cursor::new(Vec::new());
evlr.write_to(&mut cursor).unwrap();
cursor.set_position(0);
assert_eq!(evlr, Vlr::read_from(cursor, true).unwrap());
}
}