{
let value = self.0.borrow();
match &value.inner {
- ValueInner::Number(number_value) => number_value.serialize_bare(serializer),
- ValueInner::String(string_value) => string_value.s.serialize(serializer),
+ ValueInner::Datum(datum_value) => datum_value.serialize_bare(serializer),
ValueInner::Variable(variable_value) => variable_value.var_name.serialize(serializer),
ValueInner::Text(text_value) => text_value.localized.serialize(serializer),
ValueInner::Markup(markup) => markup.serialize(serializer),
where
B: EncodedString,
{
- Self::new(ValueInner::Number(NumberValue::new(datum)))
+ Self::new(ValueInner::Datum(DatumValue::new(datum)))
}
/// Returns this value with its display format set to `format`.
}
pub fn new_number(number: Option<f64>) -> Self {
- Self::new(ValueInner::Number(NumberValue::new_number(number)))
+ Self::new(ValueInner::Datum(DatumValue::new_number(number)))
}
pub fn new_integer(x: Option<f64>) -> Self {
footnotes.sort_by_key(|f| f.index);
}
pub fn with_show_value_label(mut self, show: Option<Show>) -> Self {
- let new_show = show;
- match &mut self.inner {
- ValueInner::Number(NumberValue { show, .. })
- | ValueInner::String(StringValue { show, .. }) => {
- *show = new_show;
- }
- _ => (),
+ if let Some(datum_value) = self.inner.as_datum_value_mut() {
+ datum_value.show = show;
}
self
}
}
self
}
- pub fn with_value_label(mut self, label: Option<String>) -> Self {
- match &mut self.inner {
- ValueInner::Number(NumberValue { value_label, .. })
- | ValueInner::String(StringValue { value_label, .. }) => *value_label = label.clone(),
- _ => (),
+ pub fn with_value_label(mut self, value_label: Option<String>) -> Self {
+ if let Some(datum_value) = self.inner.as_datum_value_mut() {
+ datum_value.value_label = value_label.clone()
}
self
}
pub fn with_variable_name(mut self, variable_name: Option<String>) -> Self {
match &mut self.inner {
- ValueInner::Number(NumberValue { variable, .. })
- | ValueInner::String(StringValue {
- var_name: variable, ..
- }) => *variable = variable_name,
+ ValueInner::Datum(DatumValue { variable, .. }) => *variable = variable_name,
ValueInner::Variable(VariableValue {
var_name: variable, ..
}) => {
}
pub fn var_type(&self) -> VarType {
- if let ValueInner::Number(NumberValue { datum, .. }) = &self.inner
- && datum.is_number()
+ if let Some(datum_value) = self.inner.as_datum_value()
+ && datum_value.datum.is_number()
&& self.show_label.is_none()
{
VarType::Numeric
impl Display for DisplayValue<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.inner {
- ValueInner::Number(number_value) => number_value.display(self, f),
-
- ValueInner::String(StringValue { s, .. })
- | ValueInner::Variable(VariableValue { var_name: s, .. }) => {
- match (self.show_value, self.show_label) {
- (true, None) => write!(f, "{s}"),
- (false, Some(label)) => write!(f, "{label}"),
- (true, Some(label)) => write!(f, "{s} {label}"),
- (false, None) => unreachable!(),
- }
- }
-
+ ValueInner::Datum(datum_value) => datum_value.display(self, f),
+ ValueInner::Variable(variable_value) => variable_value.display(self, f),
ValueInner::Markup(markup) => write!(f, "{markup}"),
-
ValueInner::Text(text_value) => write!(f, "{text_value}"),
-
ValueInner::Template(template_value) => template_value.display(self, f),
-
ValueInner::Empty => Ok(()),
}?;
impl Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match &self.inner {
- ValueInner::Number(_) => "Number",
- ValueInner::String(_) => "String",
+ ValueInner::Datum(_) => "Datum",
ValueInner::Variable(_) => "Variable",
ValueInner::Text(_) => "Text",
ValueInner::Markup(_) => "Markup",
/// A datum and how to display it.
#[derive(Clone, Debug, PartialEq)]
-pub struct NumberValue {
+pub struct DatumValue {
/// The datum.
pub datum: Datum<WithEncoding<ByteString>>,
pub value_label: Option<String>,
}
-impl Serialize for NumberValue {
+impl Serialize for DatumValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
}
}
-impl NumberValue {
+impl DatumValue {
pub fn new_number(number: Option<f64>) -> Self {
Self::new(&Datum::<&str>::Number(number))
}
}
}
}
-/// A string value and how to display it.
-#[derive(Clone, Debug, Serialize, PartialEq)]
-pub struct StringValue {
- /// The string value.
- ///
- /// If `hex` is true, this should contain hex digits, not raw binary data
- /// (otherwise it would be impossible to encode non-UTF-8 data).
- pub s: String,
-
- /// True if `s` is hex digits.
- pub hex: bool,
-
- /// Whether to show `s` or `value_label` or both.
- ///
- /// If this is unset, then a higher-level default is used.
- pub show: Option<Show>,
-
- /// The name of the variable that `s` came from, if any.
- pub var_name: Option<String>,
- /// The value label associated with `s`, if any.
- pub value_label: Option<String>,
-}
-impl StringValue {
- pub fn with_format(self, format: Format) -> Self {
- Self {
- hex: format.type_() == Type::AHex,
- ..self
- }
- }
-}
/// A variable name.
#[derive(Clone, Debug, Serialize, PartialEq)]
pub struct VariableValue {
pub show: Option<Show>,
}
+impl VariableValue {
+ fn display(&self, display: &DisplayValue<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ if display.show_value {
+ f.write_str(&self.var_name)?;
+ }
+ if let Some(label) = display.show_label {
+ if display.show_value {
+ f.write_char(' ')?;
+ }
+ f.write_str(label)?;
+ }
+ Ok(())
+ }
+}
+
/// A text string.
///
/// Whereas a [StringValue] is usually related to data, a `TextValue` is used
#[derive(Clone, Debug, Default, Serialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ValueInner {
- /// A numeric data value.
- Number(
- /// The number.
- NumberValue,
- ),
- /// A string data value.
- String(
- /// The string.
- StringValue,
+ /// A [Datum] value.
+ Datum(
+ /// The datum.
+ DatumValue,
),
/// A variable name.
Variable(
pub const fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
- pub fn with_format(self, format: Format) -> Self {
- match self {
- ValueInner::Number(number_value) => Self::Number(number_value.with_format(format)),
- ValueInner::String(string_value) => Self::String(string_value.with_format(format)),
- _ => self,
+ pub fn with_format(mut self, format: Format) -> Self {
+ if let Some(datum_value) = self.as_datum_value_mut() {
+ datum_value.format = format;
}
+ self
}
- pub fn with_honor_small(self, honor_small: bool) -> Self {
- match self {
- ValueInner::Number(number_value) => {
- Self::Number(number_value.with_honor_small(honor_small))
- }
- _ => self,
+ pub fn with_honor_small(mut self, honor_small: bool) -> Self {
+ if let Some(datum_value) = self.as_datum_value_mut() {
+ datum_value.honor_small = honor_small;
}
+ self
}
pub fn datum(&self) -> Option<&Datum<WithEncoding<ByteString>>> {
- match self {
- ValueInner::Number(datum_value) => Some(&datum_value.datum),
- _ => None,
- }
+ self.as_datum_value().map(|d| &d.datum)
}
fn show(&self) -> Option<Show> {
match self {
- ValueInner::Number(NumberValue { show, .. })
- | ValueInner::String(StringValue { show, .. })
+ ValueInner::Datum(DatumValue { show, .. })
| ValueInner::Variable(VariableValue { show, .. }) => *show,
_ => None,
}
}
fn value_label(&self) -> Option<&str> {
- match self {
- ValueInner::Number(NumberValue { value_label, .. })
- | ValueInner::String(StringValue { value_label, .. }) => {
- value_label.as_ref().map(String::as_str)
- }
- _ => None,
- }
+ self.as_datum_value()
+ .and_then(|d| d.value_label.as_ref().map(String::as_str))
}
fn variable_label(&self) -> Option<&str> {
_ => None,
}
}
-}
-#[derive(Clone, Debug, Default, PartialEq)]
-pub struct ValueStyle {
- pub cell_style: Option<CellStyle>,
- pub font_style: Option<FontStyle>,
- pub subscripts: Vec<String>,
- pub footnotes: Vec<Arc<Footnote>>,
-}
+ pub fn as_datum_value(&self) -> Option<&DatumValue> {
+ match self {
+ ValueInner::Datum(datum) => Some(datum),
+ _ => None,
+ }
+ }
-impl ValueStyle {
- pub fn is_empty(&self) -> bool {
- self.font_style.is_none()
- && self.cell_style.is_none()
- && self.subscripts.is_empty()
- && self.footnotes.is_empty()
+ pub fn as_datum_value_mut(&mut self) -> Option<&mut DatumValue> {
+ match self {
+ ValueInner::Datum(datum) => Some(datum),
+ _ => None,
+ }
}
-}
-impl ValueInner {
// Returns an object that will format this value. Settings on `options`
// control whether variable and value labels are included.
pub fn display(&self, options: impl IntoValueOptions) -> DisplayValue<'_> {
}
}
+#[derive(Clone, Debug, Default, PartialEq)]
+pub struct ValueStyle {
+ pub cell_style: Option<CellStyle>,
+ pub font_style: Option<FontStyle>,
+ pub subscripts: Vec<String>,
+ pub footnotes: Vec<Arc<Footnote>>,
+}
+
+impl ValueStyle {
+ pub fn is_empty(&self) -> bool {
+ self.font_style.is_none()
+ && self.cell_style.is_none()
+ && self.subscripts.is_empty()
+ && self.footnotes.is_empty()
+ }
+}
+
/// Options for displaying a [Value].
#[derive(Copy, Clone, Debug)]
pub struct ValueOptions {
use serde::Deserialize;
use crate::{
- data::Datum,
+ data::{Datum, EncodedString},
format::{self, Decimal::Dot, F8_0, F40_2, Type, UncheckedFormat},
output::pivot::{
self, Axis2, Axis3, Category, CategoryLocator, Dimension, Group, Leaf, Length, PivotTable,
self, Area, AreaStyle, CellStyle, Color, HeadingRegion, HorzAlign, Look, RowParity,
VertAlign,
},
- value::{Value, ValueInner},
+ value::Value,
},
spv::read::legacy_bin::DataValue,
};
Some(SetFormatChild::ElapsedTimeFormat(format)) => Some(format.decode()),
None => None,
};
- if let Some(format) = format {
- match &mut value.inner {
- ValueInner::Number(number) => {
- number.format = format;
+ if let Some(format) = format
+ && let Some(datum_value) = value.inner.as_datum_value_mut()
+ {
+ match &datum_value.datum {
+ Datum::Number(_) => {
+ datum_value.format = format;
}
- ValueInner::String(string) => {
+ Datum::String(string) => {
if format.type_().category() == format::Category::Date
- && let Ok(date_time) =
- NaiveDateTime::parse_from_str(&string.s, "%Y-%m-%dT%H:%M:%S%.3f")
+ && let Ok(date_time) = NaiveDateTime::parse_from_str(
+ &string.as_str(),
+ "%Y-%m-%dT%H:%M:%S%.3f",
+ )
{
value.inner = Value::new_date(date_time).with_format(format).inner;
} else if format.type_().category() == format::Category::Time
- && let Ok(time) = NaiveTime::parse_from_str(&string.s, "%H:%M:%S%.3f")
+ && let Ok(time) =
+ NaiveTime::parse_from_str(&string.as_str(), "%H:%M:%S%.3f")
{
value.inner = Value::new_time(time).with_format(format).inner;
- } else if let Ok(number) = string.s.parse::<f64>() {
+ } else if let Ok(number) = string.as_str().parse::<f64>() {
value.inner = Value::new_number(Some(number)).with_format(format).inner;
}
}
- _ => (),
}
}
}