//! 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.
}
}
-/// One data value.
-#[derive(Clone, Debug)]
-pub struct DataValue {
- /// Optional index.
- ///
- /// This is always `None` as initially decoded.
- pub index: Option<f64>,
-
- /// Data value.
- pub value: Datum<String>,
-}
-
-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<usize> {
- 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<i64, 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: 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)]
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<f64>,
+
+ /// Data value.
+ pub value: Datum<String>,
+}
+
+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<usize> {
+ 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<i64, crate::format::Format>,
+ ) -> 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<T> {
references: String,