}
mod encoded;
-pub use encoded::{
- BorrowedEncodedDatum, BorrowedEncodedString, EncodedDatum, EncodedString, OwnedEncodedDatum,
- OwnedEncodedString, QuotedEncodedDatum,
-};
+pub use encoded::{BorrowedEncodedString, EncodedString, OwnedEncodedString};
/// A [Datum] that owns its string data (if any).
pub type OwnedDatum = Datum<OwnedRawString>;
}
}
- pub fn as_encoded<'a>(&'a self, encoding: &'static Encoding) -> BorrowedEncodedDatum<'a> {
+ pub fn as_encoded<'a>(
+ &'a self,
+ encoding: &'static Encoding,
+ ) -> Datum<BorrowedEncodedString<'a>> {
match self {
- Datum::Number(number) => EncodedDatum::Number(*number),
- Datum::String(raw_string) => EncodedDatum::String(EncodedString {
- encoding,
+ Datum::Number(number) => Datum::Number(*number),
+ Datum::String(raw_string) => Datum::String(EncodedString {
raw: raw_string.borrow(),
+ encoding,
}),
}
}
}
+impl Datum<OwnedRawString> {
+ pub fn borrowed(&self) -> BorrowedDatum {
+ match self {
+ Datum::Number(number) => Datum::Number(*number),
+ Datum::String(string) => Datum::String(Borrow::borrow(string)),
+ }
+ }
+}
+
+impl<'a> Datum<&'a BorrowedRawString> {
+ pub fn borrowed(&self) -> BorrowedDatum {
+ self.clone()
+ }
+}
+
+impl Datum<OwnedEncodedString> {
+ pub fn borrowed<'a>(&'a self) -> Datum<BorrowedEncodedString<'a>> {
+ match self {
+ Datum::Number(number) => Datum::Number(*number),
+ Datum::String(string) => Datum::String(string.borrowed()),
+ }
+ }
+}
+
+impl<'a> Datum<BorrowedEncodedString<'a>> {
+ pub fn borrowed(&self) -> Datum<BorrowedEncodedString<'a>> {
+ self.clone()
+ }
+}
+
+impl<D> Datum<D>
+where
+ D: BorrowString,
+{
+ pub fn borrowed_string<'a>(&'a self) -> Datum<D::Borrowed<'a>> {
+ match self {
+ Datum::Number(number) => Datum::Number(*number),
+ Datum::String(string) => Datum::String(string.borrow_string()),
+ }
+ }
+}
+
+pub trait BorrowString {
+ type Borrowed<'a>
+ where
+ Self: 'a;
+ fn borrow_string<'a>(&'a self) -> Self::Borrowed<'a>;
+}
+
+impl BorrowString for OwnedRawString {
+ type Borrowed<'a> = &'a BorrowedRawString;
+ fn borrow_string<'a>(&'a self) -> Self::Borrowed<'a> {
+ BorrowedRawString::new(&self.0)
+ }
+}
+
+impl BorrowString for BorrowedRawString {
+ type Borrowed<'a> = &'a BorrowedRawString;
+ fn borrow_string<'a>(&'a self) -> Self::Borrowed<'a> {
+ self.clone()
+ }
+}
+
+impl BorrowString for OwnedEncodedString {
+ type Borrowed<'a> = BorrowedEncodedString<'a>;
+ fn borrow_string<'a>(&'a self) -> Self::Borrowed<'a> {
+ BorrowedEncodedString::new(self.raw.borrowed(), self.encoding)
+ }
+}
+
+impl<'b> BorrowString for BorrowedEncodedString<'b> {
+ type Borrowed<'a>
+ = BorrowedEncodedString<'b>
+ where
+ Self: 'a;
+
+ fn borrow_string<'a>(&'a self) -> Self::Borrowed<'a> {
+ self.clone()
+ }
+}
+
+pub trait AsEncodedString: Borrow<BorrowedRawString> {
+ fn as_encoded_string<'a>(&'a self) -> BorrowedEncodedString<'a>;
+}
+
+impl AsEncodedString for OwnedEncodedString {
+ fn as_encoded_string<'a>(&'a self) -> BorrowedEncodedString<'a> {
+ self.borrowed()
+ }
+}
+
+impl<'b> AsEncodedString for BorrowedEncodedString<'b> {
+ fn as_encoded_string<'a>(&'a self) -> BorrowedEncodedString<'a> {
+ self.clone()
+ }
+}
+
+impl<B> Datum<B>
+where
+ B: AsEncodedString,
+{
+ pub fn quoted<'a>(&'a self) -> QuotedDatum<'a, B> {
+ QuotedDatum(self)
+ }
+}
+
+pub struct QuotedDatum<'a, B>(&'a Datum<B>);
+
+impl<'a, B> Display for QuotedDatum<'a, B>
+where
+ B: AsEncodedString,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match &self.0 {
+ Datum::Number(None) => write!(f, "SYSMIS"),
+ Datum::Number(Some(number)) => number.display_plain().fmt(f),
+ Datum::String(string) => write!(f, "\"{}\"", string.as_encoded_string().as_str()),
+ }
+ }
+}
+
impl<B> Datum<B>
where
B: BorrowMut<OwnedRawString>,
}
impl Datum<OwnedRawString> {
- pub fn with_encoding(self, encoding: &'static Encoding) -> OwnedEncodedDatum {
+ pub fn with_encoding(self, encoding: &'static Encoding) -> Datum<OwnedEncodedString> {
match self {
- Datum::Number(number) => EncodedDatum::Number(number),
- Datum::String(raw_string) => EncodedDatum::String(raw_string.with_encoding(encoding)),
+ Datum::Number(number) => Datum::Number(number),
+ Datum::String(raw_string) => Datum::String(raw_string.with_encoding(encoding)),
}
}
}
where
B: Borrow<[Datum<OwnedRawString>]>,
{
- fn len(&self) -> usize {
+ pub fn len(&self) -> usize {
self.data.borrow().len()
}
}
impl IntoIterator for Case<Vec<Datum<OwnedRawString>>> {
- type Item = OwnedEncodedDatum;
+ type Item = Datum<OwnedEncodedString>;
type IntoIter = CaseVecIter;
}
impl Iterator for CaseVecIter {
- type Item = OwnedEncodedDatum;
+ type Item = Datum<OwnedEncodedString>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
use unicase::UniCase;
use crate::{
- data::{BorrowedEncodedDatum, Datum, OwnedEncodedDatum, OwnedRawString},
+ data::{AsEncodedString, Datum, OwnedEncodedString, OwnedRawString},
format::{DisplayPlain, Format},
identifier::{ByIdentifier, HasIdentifier, Identifier},
output::pivot::{
.with_show_value_label(Some(Show::Value));
if variable
.missing_values
- .contains(datum.as_encoded(variable.encoding()))
+ .contains(&datum.as_encoded(variable.encoding()))
{
value.add_footnote(&missing_footnote);
}
#[derive(Clone, Default, Serialize)]
pub struct MissingValues {
/// Individual missing values, up to 3 of them.
- values: Vec<OwnedEncodedDatum>,
+ values: Vec<Datum<OwnedEncodedString>>,
/// Optional range of missing values.
range: Option<MissingValueRange>,
pub fn clear(&mut self) {
*self = Self::default();
}
- pub fn values(&self) -> &[OwnedEncodedDatum] {
+ pub fn values(&self) -> &[Datum<OwnedEncodedString>] {
&self.values
}
}
pub fn new(
- mut values: Vec<OwnedEncodedDatum>,
+ mut values: Vec<Datum<OwnedEncodedString>>,
range: Option<MissingValueRange>,
) -> Result<Self, MissingValuesError> {
if values.len() > 3 {
}
}
- pub fn contains(&self, value: BorrowedEncodedDatum<'_>) -> bool {
+ pub fn contains<S>(&self, value: &Datum<S>) -> bool
+ where
+ S: AsEncodedString,
+ {
if self
.values
.iter()
// this program. If not, see <http://www.gnu.org/licenses/>.
use std::{
- borrow::Borrow,
cmp::min,
fmt::{Display, Error as FmtError, Formatter, Result as FmtResult, Write as _},
io::{Error as IoError, Write as IoWrite},
use crate::{
calendar::{calendar_offset_to_gregorian, day_of_year, month_name, short_month_name},
- data::{
- BorrowedEncodedDatum, BorrowedRawString, EncodedDatum, EncodedString, QuotedEncodedDatum,
- },
+ data::{AsEncodedString, BorrowString, Datum, QuotedDatum},
endian::{endian_to_smallvec, ToBytes},
format::{Category, DateTemplate, Decimal, Format, NumberStyle, Settings, TemplateItem, Type},
settings::{EndianSettings, Settings as PsppSettings},
};
-pub struct DisplayDatum<'a, 'b> {
+pub struct DisplayDatum<'b, B> {
format: Format,
settings: &'b Settings,
endian: EndianSettings,
- datum: BorrowedEncodedDatum<'a>,
+ datum: Datum<B>,
/// If true, the output will remove leading and trailing spaces from numeric
/// values, and trailing spaces from string values. (This might make the
}
}
+/*
impl<R> EncodedDatum<EncodedString<R>>
where
R: Borrow<BorrowedRawString>,
pub fn display_plain(&self) -> QuotedEncodedDatum<'_> {
self.quoted()
}
+}*/
+
+impl<'a, D> Datum<D>
+where
+ D: AsEncodedString + BorrowString,
+{
+ /// Returns an object that implements [Display] for printing this
+ /// [EncodedDatum] as `format`.
+ ///
+ /// [Display]: std::fmt::Display
+ pub fn display(&'a self, format: Format) -> DisplayDatum<'a, D::Borrowed<'a>>
+ where
+ D::Borrowed<'a>: AsEncodedString,
+ {
+ DisplayDatum::new(format, self.borrowed_string())
+ }
+
+ pub fn display_plain(&self) -> QuotedDatum<'_, D> {
+ self.quoted()
+ }
}
-impl Display for DisplayDatum<'_, '_> {
+impl<'a, 'b, B> Display for DisplayDatum<'b, B>
+where
+ B: AsEncodedString,
+{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
- let number = match self.datum {
- EncodedDatum::Number(number) => number,
- EncodedDatum::String(string) => {
+ let number = match &self.datum {
+ Datum::Number(number) => *number,
+ Datum::String(string) => {
if self.format.type_() == Type::AHex {
- for byte in string.as_bytes() {
+ for byte in string.as_encoded_string().as_bytes() {
write!(f, "{byte:02x}")?;
}
} else {
let quote = if self.quote_strings { "\"" } else { "" };
- let s = string.as_str();
+ let s = string.as_encoded_string();
+ let s = s.as_str();
let s = if self.trim_spaces {
s.trim_end_matches(' ')
} else {
}
}
-impl<'a, 'b> DisplayDatum<'a, 'b> {
- pub fn new(format: Format, datum: BorrowedEncodedDatum<'a>) -> Self {
+impl<'b, B> DisplayDatum<'b, B>
+where
+ B: AsEncodedString,
+{
+ pub fn new(format: Format, datum: Datum<B>) -> Self {
let settings = PsppSettings::global();
Self {
format,
use smallvec::SmallVec;
use crate::{
- data::OwnedEncodedDatum,
+ data::{Datum, OwnedEncodedString},
endian::Endian,
format::{AbstractFormat, Epoch, Format, Settings, Type, UncheckedFormat, CC},
lex::{scan::StringScanner, segment::Syntax, Punct, Token},
let format: Format = format.try_into().unwrap();
assert_eq!(tokens.get(1), Some(&Token::Punct(Punct::Colon)));
let expected = tokens[2].as_string().unwrap();
- let actual = OwnedEncodedDatum::Number(value)
+ let actual = Datum::<OwnedEncodedString>::Number(value)
.display(format)
.with_settings(&settings)
.with_endian(endian)
}
fn test_with_settings(value: f64, expected: [&str; 2], settings: &Settings) {
- let value = OwnedEncodedDatum::from(value);
+ let value = Datum::<OwnedEncodedString>::from(value);
for (expected, d) in expected.into_iter().zip([2, 1].into_iter()) {
assert_eq!(
&value
fn non_ascii_cc() {
fn test(settings: &Settings, value: f64, expected: &str) {
assert_eq!(
- &OwnedEncodedDatum::from(value)
+ &Datum::<OwnedEncodedString>::from(value)
.display(Format::new(Type::CC(CC::A), 10, 2).unwrap())
.with_settings(settings)
.to_string(),
assert_eq!(tokens.get(1), Some(&Token::Punct(Punct::Colon)));
let expected = tokens[2].as_string().unwrap();
let mut actual = SmallVec::<[u8; 16]>::new();
- OwnedEncodedDatum::Number(value)
+ Datum::<OwnedEncodedString>::Number(value)
.display(format)
.with_endian(endian)
.write(&mut actual, UTF_8)
.with_compression(self.sys_options.compression)
.write_file(&dictionary, output)?;
for case in cases {
- output.write_case(case?.into_iter().map(|datum| datum.into_raw()))?;
+ output.write_case(case?)?;
}
}
}
//! could also be a variable name or an arbitrary text string.
use std::{
- borrow::Borrow,
collections::HashMap,
fmt::{Debug, Display, Write},
io::Read,
use tlo::parse_tlo;
use crate::{
- data::{
- BorrowedRawString, Datum, EncodedDatum, EncodedString, OwnedEncodedDatum, OwnedRawString,
- },
+ data::{AsEncodedString, Datum, OwnedEncodedString, OwnedRawString},
dictionary::{VarType, Variable},
format::{Decimal, Format, Settings as FormatSettings, Type, UncheckedFormat},
settings::{Settings, Show},
variable_label: variable.label.clone(),
}))
}
- pub fn new_datum<R>(value: &EncodedDatum<EncodedString<R>>) -> Self
+ pub fn new_datum<B>(value: &Datum<B>) -> Self
where
- R: Borrow<BorrowedRawString>,
+ B: AsEncodedString,
{
match value {
- EncodedDatum::Number(number) => Self::new_number(*number),
- EncodedDatum::String(string) => Self::new_user_text(string.as_str()),
+ Datum::Number(number) => Self::new_number(*number),
+ Datum::String(string) => Self::new_user_text(string.as_encoded_string().as_str()),
}
}
pub fn new_variable_value(variable: &Variable, value: &Datum<OwnedRawString>) -> Self {
write!(
&mut buf,
"{}",
- OwnedEncodedDatum::Number(*value).display(format)
+ Datum::<OwnedEncodedString>::Number(*value).display(format)
)
.unwrap();
write!(f, "{}", buf.trim_start_matches(' '))?;
use crate::{
calendar::date_time_to_pspp,
crypto::EncryptedFile,
- data::{Case, Datum, EncodedDatum, OwnedRawString},
+ data::{Case, Datum, OwnedRawString},
dictionary::{
DictIndexMultipleResponseSet, DictIndexVariableSet, Dictionary, InvalidRole, MissingValues,
MissingValuesError, MultipleResponseType, VarWidth, Variable,
.map(|v| {
let mut value = OwnedRawString::from(v.0.as_slice());
value.resize(variable.width.as_string_width().unwrap());
- EncodedDatum::String(value.with_encoding(encoding))
+ Datum::String(value.with_encoding(encoding))
})
.collect::<Vec<_>>();
match MissingValues::new(values, None) {
use std::{
- borrow::Cow,
+ borrow::{Borrow, Cow},
collections::HashMap,
fmt::Write as _,
fs::File,
use smallvec::SmallVec;
use crate::{
- data::{Datum, OwnedEncodedDatum, OwnedRawString},
+ data::{BorrowedRawString, Datum},
dictionary::{
Alignment, Attributes, CategoryLabels, Dictionary, Measure, MultipleResponseType,
ValueLabels, VarWidth,
}
}
-impl BinWrite for Datum<OwnedRawString> {
+impl<B> BinWrite for Datum<B>
+where
+ B: Borrow<BorrowedRawString>,
+{
type Args<'a> = ();
fn write_options<W: Write + Seek>(
) -> binrw::BinResult<()> {
match self {
Datum::Number(number) => number.unwrap_or(f64::MIN).write_options(writer, endian, ()),
- Datum::String(raw_string) => raw_string.0.write_options(writer, endian, ()),
- }
- }
-}
-
-impl BinWrite for OwnedEncodedDatum {
- type Args<'a> = ();
-
- fn write_options<W: Write + Seek>(
- &self,
- writer: &mut W,
- endian: binrw::Endian,
- _: (),
- ) -> binrw::BinResult<()> {
- match self {
- Self::Number(number) => number.unwrap_or(f64::MIN).write_options(writer, endian, ()),
- Self::String(raw_string) => raw_string.as_bytes().write_options(writer, endian, ()),
+ Datum::String(raw_string) => raw_string.borrow().0.write_options(writer, endian, ()),
}
}
}
Ok(())
}
- fn write_case_uncompressed<'c>(
+ fn write_case_uncompressed<'c, B>(
&mut self,
- case: impl Iterator<Item = Datum<OwnedRawString>>,
- ) -> Result<(), BinError> {
+ case: impl Iterator<Item = Datum<B>>,
+ ) -> Result<(), BinError>
+ where
+ B: Borrow<BorrowedRawString>,
+ {
for (var, datum) in zip_eq(self.case_vars, case) {
match var {
CaseVar::Numeric => datum
.unwrap_or(f64::MIN)
.write_le(&mut self.inner)?,
CaseVar::String(encoding) => {
- let mut s = datum.as_string().unwrap().as_bytes();
+ let mut s = datum.as_string().unwrap().borrow().as_bytes();
for segment in encoding {
let data;
(data, s) = s.split_at(segment.data_bytes);
}
Ok(())
}
- fn write_case_compressed<'c>(
+ fn write_case_compressed<'c, B>(
&mut self,
- case: impl Iterator<Item = Datum<OwnedRawString>>,
- ) -> Result<(), BinError> {
+ case: impl Iterator<Item = Datum<B>>,
+ ) -> Result<(), BinError>
+ where
+ B: Borrow<BorrowedRawString>,
+ {
for (var, datum) in zip_eq(self.case_vars, case) {
match var {
CaseVar::Numeric => match datum.as_number().unwrap() {
},
CaseVar::String(encoding) => {
- let mut s = datum.as_string().unwrap().as_bytes();
+ let mut s = datum.as_string().unwrap().borrow().as_bytes();
for segment in encoding {
let data;
(data, s) = s.split_at(segment.data_bytes);
/// # Panic
///
/// Panics if [try_finish](Self::try_finish) has been called.
- pub fn write_case<'a>(
+ pub fn write_case<'a, B>(
&mut self,
- case: impl IntoIterator<Item = Datum<OwnedRawString>>,
- ) -> Result<(), BinError> {
+ case: impl IntoIterator<Item = Datum<B>>,
+ ) -> Result<(), BinError>
+ where
+ B: Borrow<BorrowedRawString>,
+ {
match self.inner.as_mut().unwrap() {
Either::Left(inner) => {
let mut inner =