X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=rust%2Fsrc%2Fformat.rs;h=9f285a9dd6710624564f90fea197b56307bad82c;hb=e0cbdf0daefcca81be9572aab0deedf945687f5a;hp=81f50ba0ba23946add74c29ebaff9fdbaf4b1ad0;hpb=b44494fd38aed720a165fc41a34efb8f095b6132;p=pspp diff --git a/rust/src/format.rs b/rust/src/format.rs index 81f50ba0ba..9f285a9dd6 100644 --- a/rust/src/format.rs +++ b/rust/src/format.rs @@ -5,11 +5,14 @@ use std::{ use thiserror::Error as ThisError; -use crate::raw::VarType; +use crate::{ + cooked::VarWidth, + raw::{self, VarType}, +}; #[derive(ThisError, Debug)] pub enum Error { - #[error("Unknown format type {value}")] + #[error("Unknown format type {value}.")] UnknownFormat { value: u16 }, #[error("Output format {0} specifies width {}, but {} requires an even width.", .0.w, .0.format)] @@ -36,12 +39,6 @@ pub enum Error { #[error("Numeric variable is not compatible with string format {0}.")] UnnamedVariableNotCompatibleWithStringFormat(Format), - #[error("String variable {variable} is not compatible with numeric format {format}.")] - NamedVariableNotCompatibleWithNumericFormat { variable: String, format: Format }, - - #[error("Numeric variable {variable} is not compatible with string format {format}.")] - NamedVariableNotCompatibleWithStringFormat { variable: String, format: Format }, - #[error("String variable {variable} with width {width} is not compatible with format {bad_spec}. Use format {good_spec} instead.")] NamedStringVariableBadSpecWidth { variable: String, @@ -173,20 +170,18 @@ pub enum Format { AHex, } -pub const MAX_STRING: Width = 32767; +pub type Width = u16; +pub type SignedWidth = i16; -type Width = u16; -type SignedWidth = i16; - -type Decimals = u8; +pub type Decimals = u8; impl Format { pub fn max_width(self) -> Width { match self { Self::P | Self::PK | Self::PIBHex | Self::RBHex => 16, Self::IB | Self::PIB | Self::RB => 8, - Self::A => MAX_STRING, - Self::AHex => MAX_STRING * 2, + Self::A => 32767, + Self::AHex => 32767 * 2, _ => 40, } } @@ -305,36 +300,20 @@ impl Format { pub fn var_type(self) -> VarType { match self { Self::A | Self::AHex => VarType::String, - _ => VarType::Number, + _ => VarType::Numeric, } } - pub fn check_type_compatibility( - self, - variable: Option<&str>, - var_type: VarType, - ) -> Result<(), Error> { + /// Checks whether this format is valid for a variable with the given + /// `var_type`. + pub fn check_type_compatibility(self, var_type: VarType) -> Result<(), Error> { let my_type = self.var_type(); match (my_type, var_type) { - (VarType::Number, VarType::String) => { - if let Some(variable) = variable { - Err(Error::NamedVariableNotCompatibleWithNumericFormat { - variable: variable.into(), - format: self, - }) - } else { - Err(Error::UnnamedVariableNotCompatibleWithNumericFormat(self)) - } + (VarType::Numeric, VarType::String) => { + Err(Error::UnnamedVariableNotCompatibleWithNumericFormat(self)) } - (VarType::String, VarType::Number) => { - if let Some(variable) = variable { - Err(Error::NamedVariableNotCompatibleWithStringFormat { - variable: variable.into(), - format: self, - }) - } else { - Err(Error::UnnamedVariableNotCompatibleWithStringFormat(self)) - } + (VarType::String, VarType::Numeric) => { + Err(Error::UnnamedVariableNotCompatibleWithStringFormat(self)) } _ => Ok(()), } @@ -404,6 +383,21 @@ impl Spec { self.d } + pub fn default_for_width(var_width: VarWidth) -> Self { + match var_width { + VarWidth::Numeric => Spec { + format: Format::F, + w: 8, + d: 2, + }, + VarWidth::String(w) => Spec { + format: Format::A, + w, + d: 0, + }, + } + } + pub fn fixed_from(source: &UncheckedSpec) -> Self { let UncheckedSpec { format, w, d } = *source; let (min, max) = format.width_range().into_inner(); @@ -418,11 +412,11 @@ impl Spec { Self { format, w, d } } - pub fn var_width(self) -> Width { + pub fn var_width(self) -> VarWidth { match self.format { - Format::A => self.w, - Format::AHex => self.w / 2, - _ => 0, + Format::A => VarWidth::String(self.w), + Format::AHex => VarWidth::String(self.w / 2), + _ => VarWidth::Numeric, } } @@ -430,33 +424,29 @@ impl Spec { self.format.var_type() } - pub fn check_width_compatibility(self, variable: Option<&str>, w: Width) -> Result<(), Error> { - self.format.check_type_compatibility(variable, self.var_type())?; - let expected_width = self.var_width(); - if w != expected_width { - let bad_spec = self; - let good_spec = if self.format == Format::A { - Spec { w, ..self } - } else { - Spec { w: w * 2, ..self } - }; - if let Some(variable) = variable { - Err(Error::NamedStringVariableBadSpecWidth { - variable: variable.into(), - width: w, - bad_spec, - good_spec, - }) - } else { - Err(Error::UnnamedStringVariableBadSpecWidth { + /// Checks whether this format specification is valid for a variable with + /// width `var_width`. + pub fn check_width_compatibility(self, var_width: VarWidth) -> Result { + // Verify that the format is right for the variable's type. + self.format.check_type_compatibility(var_width.into())?; + + if let VarWidth::String(w) = var_width { + if var_width != self.var_width() { + let bad_spec = self; + let good_spec = if self.format == Format::A { + Spec { w, ..self } + } else { + Spec { w: w * 2, ..self } + }; + return Err(Error::UnnamedStringVariableBadSpecWidth { width: w, bad_spec, good_spec, - }) + }); } - } else { - Ok(()) } + + Ok(self) } } @@ -553,14 +543,15 @@ pub struct UncheckedSpec { pub d: Decimals, } -impl TryFrom for UncheckedSpec { +impl TryFrom for UncheckedSpec { type Error = Error; - fn try_from(source: u32) -> Result { - let raw_format = (source >> 16) as u16; + fn try_from(raw: raw::Spec) -> Result { + let raw = raw.0; + let raw_format = (raw >> 16) as u16; let format = raw_format.try_into()?; - let w = ((source >> 8) & 0xff) as Width; - let d = (source & 0xff) as Decimals; + let w = ((raw >> 8) & 0xff) as Width; + let d = (raw & 0xff) as Decimals; Ok(Self { format, w, d }) } }