}
impl EncodedDatum {
- pub fn into_raw(self) -> Datum {
+ pub fn into_raw(self) -> Datum<RawString> {
match self {
EncodedDatum::Number(number) => Datum::Number(number),
EncodedDatum::String(encoded_string) => Datum::String(encoded_string.into()),
/// The value of a [Variable](crate::dictionary::Variable).
#[derive(Clone)]
-pub enum Datum {
+pub enum Datum<B>
+where
+ B: Borrow<RawStr>,
+{
/// A numeric value.
Number(
/// A number, or `None` for the system-missing value.
/// A string value.
String(
/// The value, in the variable's encoding.
- RawString,
+ B,
),
}
-impl Debug for Datum {
+impl<B> Debug for Datum<B>
+where
+ B: Borrow<RawStr> + Debug,
+{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Self::Number(Some(number)) => write!(f, "{number:?}"),
}
}
-impl Serialize for Datum {
+impl<B> Serialize for Datum<B>
+where
+ B: Borrow<RawStr> + Serialize,
+{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
}
}
-impl PartialEq for Datum {
+impl<B> PartialEq for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Number(Some(l0)), Self::Number(Some(r0))) => {
OrderedFloat(*l0) == OrderedFloat(*r0)
}
(Self::Number(None), Self::Number(None)) => true,
- (Self::String(l0), Self::String(r0)) => l0 == r0,
+ (Self::String(l0), Self::String(r0)) => l0.borrow() == r0.borrow(),
_ => false,
}
}
}
-impl Eq for Datum {}
+impl<B> Eq for Datum<B> where B: Borrow<RawStr> {}
-impl PartialOrd for Datum {
+impl<B> PartialOrd for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
-impl Ord for Datum {
+impl<B> Ord for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Self::Number(a), Self::Number(b)) => match (a, b) {
},
(Self::Number(_), Self::String(_)) => Ordering::Less,
(Self::String(_), Self::Number(_)) => Ordering::Greater,
- (Self::String(a), Self::String(b)) => a.cmp(b),
+ (Self::String(a), Self::String(b)) => a.borrow().cmp(b.borrow()),
}
}
}
-impl Hash for Datum {
+impl<B> Hash for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Number(number) => number.map(OrderedFloat).hash(state),
- Self::String(string) => string.hash(state),
+ Self::String(string) => string.borrow().hash(state),
}
}
}
-impl Datum {
+impl Datum<RawString> {
/// Constructs a new numerical [Datum] for the system-missing value.
pub const fn sysmis() -> Self {
Self::Number(None)
/// Compares this datum and `other` for equality, ignoring trailing ASCII
/// spaces in either, if they are both strings, for the purpose of
/// comparison.
- pub fn eq_ignore_trailing_spaces(&self, other: &Datum) -> bool {
+ pub fn eq_ignore_trailing_spaces<B2>(&self, other: &Datum<RawString>) -> bool {
match (self, other) {
(Self::String(a), Self::String(b)) => a.eq_ignore_trailing_spaces(b),
_ => self == other,
}
}
-impl From<f64> for Datum {
+impl<B> From<f64> for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn from(number: f64) -> Self {
Some(number).into()
}
}
-impl From<Option<f64>> for Datum {
+impl<B> From<Option<f64>> for Datum<B>
+where
+ B: Borrow<RawStr>,
+{
fn from(value: Option<f64>) -> Self {
Self::Number(value)
}
}
-impl From<&str> for Datum {
+impl<B> From<&str> for Datum<B>
+where
+ B: Borrow<RawStr> + for<'a> From<&'a [u8]>,
+{
fn from(value: &str) -> Self {
value.as_bytes().into()
}
}
-impl From<&[u8]> for Datum {
+impl<B> From<&[u8]> for Datum<B>
+where
+ B: Borrow<RawStr> + for<'a> From<&'a [u8]>,
+{
fn from(value: &[u8]) -> Self {
Self::String(value.into())
}
/// order.
///
/// [Dictionary]: crate::dictionary::Dictionary
- pub Vec<Datum>,
+ pub Vec<Datum<RawString>>,
);
impl RawCase {
- pub fn as_encoding(&self, encoding: &'static Encoding) -> Case<&'_ [Datum]> {
+ pub fn as_encoding(&self, encoding: &'static Encoding) -> Case<&'_ [Datum<RawString>]> {
Case {
encoding,
data: &self.0,
}
}
- pub fn with_encoding(self, encoding: &'static Encoding) -> Case<Vec<Datum>> {
+ pub fn with_encoding(self, encoding: &'static Encoding) -> Case<Vec<Datum<RawString>>> {
Case {
encoding,
data: self.0,
pub struct Case<B>
where
- B: Borrow<[Datum]>,
+ B: Borrow<[Datum<RawString>]>,
{
encoding: &'static Encoding,
data: B,
impl<B> Case<B>
where
- B: Borrow<[Datum]>,
+ B: Borrow<[Datum<RawString>]>,
{
fn len(&self) -> usize {
self.data.borrow().len()
}
}
-impl IntoIterator for Case<Vec<Datum>> {
+impl IntoIterator for Case<Vec<Datum<RawString>>> {
type Item = EncodedDatum;
type IntoIter = CaseVecIter;
pub struct CaseVecIter {
encoding: &'static Encoding,
- iter: std::vec::IntoIter<Datum>,
+ iter: std::vec::IntoIter<Datum<RawString>>,
}
impl Iterator for CaseVecIter {
use unicase::UniCase;
use crate::{
- data::{Datum, EncodedDat, EncodedDatum},
+ data::{Datum, EncodedDat, EncodedDatum, RawString},
format::{DisplayPlain, Format},
identifier::{ByIdentifier, HasIdentifier, Identifier},
output::pivot::{
/// one value (the "counted value") means that the box was checked, and any
/// other value means that it was not.
MultipleDichotomy {
- datum: Datum,
+ datum: Datum<RawString>,
labels: CategoryLabels,
},
}
#[derive(Clone, Default, PartialEq, Eq, Serialize)]
-pub struct ValueLabels(pub HashMap<Datum, String>);
+pub struct ValueLabels(pub HashMap<Datum<RawString>, String>);
impl ValueLabels {
pub fn new() -> Self {
self.0.is_empty()
}
- pub fn get(&self, datum: &Datum) -> Option<&str> {
+ pub fn get(&self, datum: &Datum<RawString>) -> Option<&str> {
self.0.get(datum).map(|s| s.as_str())
}
- pub fn insert(&mut self, datum: Datum, label: String) -> Option<String> {
+ pub fn insert(&mut self, datum: Datum<RawString>, label: String) -> Option<String> {
self.0.insert(datum, label)
}
}
}
- pub fn default_value(&self) -> Datum {
+ pub fn default_value(&self) -> Datum<RawString> {
match self.var_type() {
VarType::Numeric => Datum::sysmis(),
VarType::String => Datum::String(RawString::default()),
Ok(self)
}
- pub fn default_value(&self) -> Datum {
+ pub fn default_value(&self) -> Datum<RawString> {
match self.var_width() {
VarWidth::Numeric => Datum::sysmis(),
VarWidth::String(width) => Datum::String(RawString::spaces(width as usize)),
use crate::{
calendar::{calendar_gregorian_to_offset, DateError},
- data::{Datum, EncodedStr, EncodedString},
+ data::{Datum, EncodedStr, EncodedString, RawString},
endian::{Endian, Parse},
format::{DateTemplate, Decimals, Settings, TemplateItem, Type},
settings::{EndianSettings, Settings as PsppSettings},
/// input into UTF-8, but this will screw up parsing of binary formats,
/// because recoding bytes from (e.g.) windows-1252 into UTF-8, and then
/// interpreting them as a binary number yields nonsense.
- pub fn parse<'b, T>(&self, input: T) -> Result<Datum, ParseError>
+ pub fn parse<'b, T>(&self, input: T) -> Result<Datum<RawString>, ParseError>
where
T: Into<EncodedStr<'b>>,
{
})
}
- fn parse_number(&self, input: &str, type_: Type) -> Result<Datum, ParseErrorKind> {
+ fn parse_number(&self, input: &str, type_: Type) -> Result<Datum<RawString>, ParseErrorKind> {
let style = self.settings.number_style(type_);
let input = input.trim();
}
}
- fn parse_n(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_n(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
match input.chars().find(|c| !c.is_ascii_digit()) {
None => Ok(Datum::Number(Some(input.parse().unwrap()))),
Some(nondigit) => Err(ParseErrorKind::Nondigit(nondigit)),
}
}
- fn parse_z(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_z(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
let input = input.trim();
if input.is_empty() || input == "." {
return Ok(Datum::sysmis());
}
}
- fn parse_pk(&self, input: &[u8]) -> Result<Datum, ParseErrorKind> {
+ fn parse_pk(&self, input: &[u8]) -> Result<Datum<RawString>, ParseErrorKind> {
let number = Self::parse_bcd(input)?;
Ok(Datum::Number(Some(self.apply_decimals(number as f64))))
}
- fn parse_p(&self, input: &[u8]) -> Result<Datum, ParseErrorKind> {
+ fn parse_p(&self, input: &[u8]) -> Result<Datum<RawString>, ParseErrorKind> {
if input.is_empty() {
return Ok(Datum::Number(None));
};
}
}
- fn parse_ib(&self, input: &[u8]) -> Result<Datum, ParseErrorKind> {
+ fn parse_ib(&self, input: &[u8]) -> Result<Datum<RawString>, ParseErrorKind> {
let number = self.parse_binary(input);
let sign_bit = 1 << (input.len() * 8 - 1);
let number = if (number & sign_bit) == 0 {
Ok(Datum::Number(Some(self.apply_decimals(number as f64))))
}
- fn parse_pib(&self, input: &[u8]) -> Result<Datum, ParseErrorKind> {
+ fn parse_pib(&self, input: &[u8]) -> Result<Datum<RawString>, ParseErrorKind> {
let number = self.parse_binary(input);
Ok(Datum::Number(Some(self.apply_decimals(number as f64))))
}
- fn parse_rb(&self, input: &[u8]) -> Result<Datum, ParseErrorKind> {
+ fn parse_rb(&self, input: &[u8]) -> Result<Datum<RawString>, ParseErrorKind> {
let mut bytes = [0; 8];
let len = input.len().min(8);
bytes[..len].copy_from_slice(&input[..len]);
Ok(Datum::Number(number))
}
- fn parse_ahex(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_ahex(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
let mut result = Vec::with_capacity(input.len() / 2);
let mut iter = input.chars();
while let Some(hi) = iter.next() {
}
}
- fn parse_pibhex(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_pibhex(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
self.parse_hex(input)
.map(|value| Datum::Number(value.map(|number| number as f64)))
}
- fn parse_rbhex(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_rbhex(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
self.parse_hex(input)
.map(|value| Datum::Number(value.map(f64::from_bits)))
}
- fn parse_date(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_date(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
let mut p = StrParser(input.trim());
if p.0.is_empty() || p.0 == "." {
return Ok(Datum::sysmis());
Ok(time + seconds)
}
- fn parse_wkday(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_wkday(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
let mut p = StrParser(input.trim());
if p.0.is_empty() || p.0 == "." {
Ok(Datum::sysmis())
}
}
- fn parse_month(&self, input: &str) -> Result<Datum, ParseErrorKind> {
+ fn parse_month(&self, input: &str) -> Result<Datum<RawString>, ParseErrorKind> {
let mut p = StrParser(input.trim());
if p.0.is_empty() || p.0 == "." {
Ok(Datum::sysmis())
use tlo::parse_tlo;
use crate::{
- data::{Datum, EncodedDat, EncodedDatum},
+ data::{Datum, EncodedDat, EncodedDatum, RawString},
dictionary::{VarType, Variable},
format::{Decimal, Format, Settings as FormatSettings, Type, UncheckedFormat},
settings::{Settings, Show},
EncodedDat::String(string) => Self::new_user_text(string.as_str()),
}
}
- pub fn new_variable_value(variable: &Variable, value: &Datum) -> Self {
+ pub fn new_variable_value(variable: &Variable, value: &Datum<RawString>) -> Self {
let var_name = Some(variable.name.as_str().into());
let value_label = variable.value_labels.get(value).map(String::from);
match value {
}
impl Iterator for Cases {
- type Item = Result<Case<Vec<Datum>>, raw::Error>;
+ type Item = Result<Case<Vec<Datum<RawString>>>, raw::Error>;
fn next(&mut self) -> Option<Self::Item> {
self.inner
/// Decodes a `RawDatum` into a [Datum] given that we now know the string
/// width.
- pub fn decode(&self, width: VarWidth) -> Datum {
+ pub fn decode(&self, width: VarWidth) -> Datum<RawString> {
match self {
Self::Number(x) => Datum::Number(*x),
Self::String(s) => {
}
}
-impl Datum {
+impl Datum<RawString> {
fn read_case<R: Read + Seek>(
reader: &mut R,
case_vars: &[CaseVar],
#[derive(Clone, Debug, Default, Serialize)]
pub struct RawMissingValues {
/// Individual missing values, up to 3 of them.
- pub values: Vec<Datum>,
+ pub values: Vec<Datum<RawString>>,
/// Optional range of missing values.
pub range: Option<MissingValueRange>,
}
impl RawMissingValues {
- pub fn new(values: Vec<Datum>, range: Option<MissingValueRange>) -> Self {
+ pub fn new(values: Vec<Datum<RawString>>, range: Option<MissingValueRange>) -> Self {
Self { values, range }
}
use std::{
- borrow::Cow,
+ borrow::{Borrow, Cow},
collections::HashMap,
fmt::Write as _,
fs::File,
use smallvec::SmallVec;
use crate::{
- data::{Dat, Datum, EncodedDatum},
+ data::{Dat, Datum, EncodedDatum, RawStr, RawString},
dictionary::{
Alignment, Attributes, CategoryLabels, Dictionary, Measure, MultipleResponseType,
ValueLabels, VarWidth,
}
}
-impl BinWrite for Datum {
+impl BinWrite for Datum<RawString> {
type Args<'a> = ();
fn write_options<W: Write + Seek>(
fn write_case_uncompressed<'c>(
&mut self,
- case: impl Iterator<Item = Datum>,
+ case: impl Iterator<Item = Datum<RawString>>,
) -> Result<(), BinError> {
for (var, datum) in zip_eq(self.case_vars, case) {
match var {
}
fn write_case_compressed<'c>(
&mut self,
- case: impl Iterator<Item = Datum>,
+ case: impl Iterator<Item = Datum<RawString>>,
) -> Result<(), BinError> {
for (var, datum) in zip_eq(self.case_vars, case) {
match var {
/// Panics if [try_finish](Self::try_finish) has been called.
pub fn write_case<'a>(
&mut self,
- case: impl IntoIterator<Item = Datum>,
+ case: impl IntoIterator<Item = Datum<RawString>>,
) -> Result<(), BinError> {
match self.inner.as_mut().unwrap() {
Either::Left(inner) => {