From 6685fe8d9f7be2e6e77e556e43ebaacde5f639da Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 3 Jan 2026 11:36:37 -0800 Subject: [PATCH] cleanup --- rust/pspp/src/cli/show_spv.rs | 8 ++- rust/pspp/src/spv/read/legacy_bin.rs | 76 +--------------------------- rust/pspp/src/spv/read/legacy_xml.rs | 71 +++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 77 deletions(-) diff --git a/rust/pspp/src/cli/show_spv.rs b/rust/pspp/src/cli/show_spv.rs index a62c18e7a6..95a87bff65 100644 --- a/rust/pspp/src/cli/show_spv.rs +++ b/rust/pspp/src/cli/show_spv.rs @@ -24,8 +24,12 @@ use pspp::{ }, spv::{ SpvArchive, - legacy_bin::{DataValue, LegacyBin}, - read::{ReadSeek, legacy_xml::Visualization, structure::OutlineItem}, + legacy_bin::LegacyBin, + read::{ + ReadSeek, + legacy_xml::{DataValue, Visualization}, + structure::OutlineItem, + }, }, }; use std::{ diff --git a/rust/pspp/src/spv/read/legacy_bin.rs b/rust/pspp/src/spv/read/legacy_bin.rs index ed690c2499..aa67d75402 100644 --- a/rust/pspp/src/spv/read/legacy_bin.rs +++ b/rust/pspp/src/spv/read/legacy_bin.rs @@ -1,20 +1,14 @@ //! Legacy binary data. -use std::{ - collections::HashMap, - io::{Read, Seek, SeekFrom}, -}; +use std::io::{Read, Seek, SeekFrom}; use binrw::{BinRead, BinResult, binread}; -use chrono::{NaiveDateTime, NaiveTime}; use displaydoc::Display; use encoding_rs::UTF_8; use indexmap::IndexMap; use crate::{ data::Datum, - format::{Category, Format}, - output::pivot::value::Value, - spv::read::light::{U32String, decode_format, parse_vec}, + spv::read::light::{U32String, parse_vec}, }; /// A warning decoding a legacy binary member. @@ -142,72 +136,6 @@ impl LegacyBin { } } -/// One data value. -#[derive(Clone, Debug)] -pub struct DataValue { - /// Optional index. - /// - /// This is always `None` as initially decoded. - pub index: Option, - - /// Data value. - pub value: Datum, -} - -impl DataValue { - /// Category index, if any. This is the numeric value of the datum, if - /// there is one, falling back to the index. - pub fn category(&self) -> Option { - match &self.value { - Datum::Number(number) => *number, - _ if self.index.is_some() => self.index, - Datum::String(string) => { - // This only comes up in a few cases which indicate something - // odd might have happened to the table in the SPV files. - string.parse().ok() - } - } - .and_then(|v| (v >= 0.0 && v < usize::MAX as f64).then_some(v as usize)) - } - - /// Interprets this data value as a [Format], first by looking it up in - /// `format_map` and otherwise by interpreting it as a [Format] directly. - /// - /// This should probably be a method on some hypothetical FormatMap. - pub fn as_format(&self, format_map: &HashMap) -> Format { - let f = match &self.value { - Datum::Number(Some(number)) => *number as i64, - Datum::Number(None) => 0, - Datum::String(s) => s.parse().unwrap_or_default(), - }; - match format_map.get(&f) { - Some(format) => *format, - None => decode_format(f as u32, &mut |_| () /*XXX*/), - } - } - - /// Returns this data value interpreted using `format`. - pub fn as_pivot_value(&self, format: Format) -> Value { - if format.type_().category() == Category::Date - && let Some(s) = self.value.as_string() - && let Ok(date_time) = - NaiveDateTime::parse_from_str(s.as_str(), "%Y-%m-%dT%H:%M:%S%.3f") - { - Value::new_date(date_time) - } else if format.type_().category() == Category::Time - && let Some(s) = self.value.as_string() - && let Ok(time) = NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S%.3f") - { - Value::new_time(time) - } else if !self.value.is_sysmis() { - Value::new_datum(&self.value) - } else { - Value::new_empty() - } - .with_format(format) - } -} - #[binread] #[br(little)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/rust/pspp/src/spv/read/legacy_xml.rs b/rust/pspp/src/spv/read/legacy_xml.rs index 93202ca2c5..e4c575a090 100644 --- a/rust/pspp/src/spv/read/legacy_xml.rs +++ b/rust/pspp/src/spv/read/legacy_xml.rs @@ -41,9 +41,78 @@ use crate::{ look::{self, Area, AreaStyle, CellStyle, Color, HorzAlign, Look, RowParity, VertAlign}, value::Value, }, - spv::read::legacy_bin::DataValue, + spv::read::light::decode_format, }; +/// One data value. +#[derive(Clone, Debug)] +pub struct DataValue { + /// Optional index. + /// + /// This is always `None` as initially decoded. + pub index: Option, + + /// Data value. + pub value: Datum, +} + +impl DataValue { + /// Category index, if any. This is the numeric value of the datum, if + /// there is one, falling back to the index. + pub fn category(&self) -> Option { + match &self.value { + Datum::Number(number) => *number, + _ if self.index.is_some() => self.index, + Datum::String(string) => { + // This only comes up in a few cases which indicate something + // odd might have happened to the table in the SPV files. + string.parse().ok() + } + } + .and_then(|v| (v >= 0.0 && v < usize::MAX as f64).then_some(v as usize)) + } + + /// Interprets this data value as a [Format], first by looking it up in + /// `format_map` and otherwise by interpreting it as a [Format] directly. + /// + /// This should probably be a method on some hypothetical FormatMap. + pub fn as_format( + &self, + format_map: &HashMap, + ) -> crate::format::Format { + let f = match &self.value { + Datum::Number(Some(number)) => *number as i64, + Datum::Number(None) => 0, + Datum::String(s) => s.parse().unwrap_or_default(), + }; + match format_map.get(&f) { + Some(format) => *format, + None => decode_format(f as u32, &mut |_| () /*XXX*/), + } + } + + /// Returns this data value interpreted using `format`. + pub fn as_pivot_value(&self, format: crate::format::Format) -> Value { + if format.type_().category() == crate::format::Category::Date + && let Some(s) = self.value.as_string() + && let Ok(date_time) = + NaiveDateTime::parse_from_str(s.as_str(), "%Y-%m-%dT%H:%M:%S%.3f") + { + Value::new_date(date_time) + } else if format.type_().category() == crate::format::Category::Time + && let Some(s) = self.value.as_string() + && let Ok(time) = NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S%.3f") + { + Value::new_time(time) + } else if !self.value.is_sysmis() { + Value::new_datum(&self.value) + } else { + Value::new_empty() + } + .with_format(format) + } +} + #[derive(Debug)] struct Ref { references: String, -- 2.30.2