From 9835922fcb03d7403aac68a1f3c7605bf5d111eb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 25 Mar 2025 09:17:00 -0700 Subject: [PATCH] Implement IB. --- rust/pspp/src/endian.rs | 24 ++++++++++++++++++++++++ rust/pspp/src/format/display.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/rust/pspp/src/endian.rs b/rust/pspp/src/endian.rs index ba47a3001a..ae3cd99c14 100644 --- a/rust/pspp/src/endian.rs +++ b/rust/pspp/src/endian.rs @@ -1,3 +1,5 @@ +use smallvec::SmallVec; + /// The endianness for integer and floating-point numbers in SPSS system files. /// /// SPSS system files can declare IBM 370 and DEC VAX floating-point @@ -37,11 +39,33 @@ impl Endian { _ => None, } } + + pub fn to_smallvec(self, mut value: u64, n: usize) -> SmallVec<[u8; 16]> { + debug_assert!(n <= 8); + let mut vec = SmallVec::new(); + value <<= 8 * (8 - n); + for _ in 0..n { + vec.push((value >> 56) as u8); + value <<= 8; + } + if self == Endian::Little { + vec.reverse(); + } + vec + } } pub trait ToBytes { fn to_bytes(self, value: T) -> [u8; N]; } +impl ToBytes for Endian { + fn to_bytes(self, value: u64) -> [u8; 8] { + match self { + Endian::Big => u64::to_be_bytes(value), + Endian::Little => u64::to_le_bytes(value), + } + } +} impl ToBytes for Endian { fn to_bytes(self, value: i64) -> [u8; 8] { match self { diff --git a/rust/pspp/src/format/display.rs b/rust/pspp/src/format/display.rs index c7a42b836a..ca1545240a 100644 --- a/rust/pspp/src/format/display.rs +++ b/rust/pspp/src/format/display.rs @@ -560,6 +560,7 @@ impl<'a, 'b> DisplayValue<'a, 'b> { match self.format.type_() { Type::P => Some(self.p(number)), Type::PK => Some(self.pk(number)), + Type::IB => Some(self.ib(number)), _ => None, } } @@ -613,6 +614,26 @@ impl<'a, 'b> DisplayValue<'a, 'b> { let (_valid, output) = self.bcd(number, self.format.w() * 2); output } + + fn ib(&self, number: Option) -> SmallVec<[u8; 16]> { + let number = number.map_or(0.0, |number| (number * power10(self.format.d())).round()); + let number = if number >= power256(self.format.w) / 2.0 - 1.0 + || number < -power256(self.format.w) / 2.0 + { + 0.0 + } else { + number + }; + let integer = number.abs() as u64; + let integer = if number < 0.0 { + (-(integer as i64)) as u64 + } else { + integer + }; + PsppSettings::global() + .output_integer_format + .to_smallvec(integer, self.format.w()) + } } struct LegacyFormat { @@ -1008,6 +1029,7 @@ mod test { segment::Syntax, token::{Punct, Token}, }, + settings::Settings as PsppSettings, }; fn test(name: &str) { @@ -1204,6 +1226,7 @@ mod test { let input = BufReader::new(File::open(&filename).unwrap()); let mut value = None; let mut value_name = String::new(); + for (line_number, line) in input.lines().map(|r| r.unwrap()).enumerate() { let line = line.trim(); let line_number = line_number + 1; @@ -1259,4 +1282,9 @@ mod test { fn test_pk() { test_binhex("pk.txt"); } + + #[test] + fn test_ib() { + test_binhex("ib.txt"); + } } -- 2.30.2