use std::io::Read;
use crate::error::{Result, SpssError};
use crate::io_utils::{self, SavReader};
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum RawValue {
Numeric(f64),
String(Vec<u8>),
}
#[derive(Debug, Clone)]
pub struct ValueLabelSet {
pub labels: Vec<(RawValue, Vec<u8>)>,
pub variable_indices: Vec<usize>,
}
pub fn parse_value_labels<R: Read>(reader: &mut SavReader<R>) -> Result<Vec<(RawValue, Vec<u8>)>> {
let count = reader.read_i32()? as usize;
let mut labels = Vec::with_capacity(count);
for _ in 0..count {
let value_bytes = reader.read_8_bytes()?;
let mut label_len_buf = [0u8; 1];
reader.read_exact(&mut label_len_buf)?;
let label_len = label_len_buf[0] as usize;
let padded_label_len = io_utils::round_up(label_len + 1, 8) - 1;
let label_data = reader.read_bytes(padded_label_len)?;
let label_bytes = label_data[..label_len].to_vec();
let value = RawValue::Numeric(f64::from_le_bytes(value_bytes));
labels.push((value, label_bytes));
}
Ok(labels)
}
pub fn parse_value_label_variables<R: Read>(reader: &mut SavReader<R>) -> Result<Vec<usize>> {
let count = reader.read_i32()? as usize;
if count == 0 {
return Err(SpssError::InvalidValueLabel(
"type 4 record with 0 variables".to_string(),
));
}
let mut indices = Vec::with_capacity(count);
for _ in 0..count {
let index = reader.read_i32()?;
if index < 1 {
return Err(SpssError::InvalidValueLabel(format!(
"invalid variable index {index} in type 4 record"
)));
}
indices.push((index - 1) as usize);
}
Ok(indices)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_value_labels() {
let mut buf = Vec::new();
buf.extend_from_slice(&2_i32.to_le_bytes());
buf.extend_from_slice(&1.0_f64.to_le_bytes());
buf.push(4); buf.extend_from_slice(b"Male");
buf.extend_from_slice(&[0u8; 3]);
buf.extend_from_slice(&2.0_f64.to_le_bytes());
buf.push(6); buf.extend_from_slice(b"Female");
buf.push(0);
let mut reader = SavReader::new(&buf[..]);
let labels = parse_value_labels(&mut reader).unwrap();
assert_eq!(labels.len(), 2);
assert_eq!(labels[0].1, b"Male");
assert_eq!(labels[1].1, b"Female");
}
#[test]
fn test_parse_value_label_variables() {
let mut buf = Vec::new();
buf.extend_from_slice(&3_i32.to_le_bytes()); buf.extend_from_slice(&1_i32.to_le_bytes()); buf.extend_from_slice(&5_i32.to_le_bytes()); buf.extend_from_slice(&10_i32.to_le_bytes());
let mut reader = SavReader::new(&buf[..]);
let indices = parse_value_label_variables(&mut reader).unwrap();
assert_eq!(indices, vec![0, 4, 9]);
}
}