work on datum
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 25 Jul 2025 14:47:48 +0000 (07:47 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 25 Jul 2025 14:47:48 +0000 (07:47 -0700)
rust/pspp/src/data.rs
rust/pspp/src/format/parse.rs

index 38510e6b74d71c856f25081f13c39b41e69e8c7b..b907fc513efea87b32c4a3ef088aaedcff1fa959 100644 (file)
@@ -498,12 +498,12 @@ impl<'a> PartialEq for EncodedDat<'a> {
 
 impl<'a> Eq for EncodedDat<'a> {}
 
+pub type OwnedDatum = Datum<RawString>;
+pub type BorrowedDatum<'a> = Datum<&'a RawStr>;
+
 /// The value of a [Variable](crate::dictionary::Variable).
 #[derive(Clone)]
-pub enum Datum<B>
-where
-    B: Borrow<RawStr>,
-{
+pub enum Datum<B> {
     /// A numeric value.
     Number(
         /// A number, or `None` for the system-missing value.
@@ -518,7 +518,7 @@ where
 
 impl<B> Debug for Datum<B>
 where
-    B: Borrow<RawStr> + Debug,
+    B: Debug,
 {
     fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
         match self {
@@ -531,7 +531,7 @@ where
 
 impl<B> Serialize for Datum<B>
 where
-    B: Borrow<RawStr> + Serialize,
+    B: Serialize,
 {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -544,17 +544,18 @@ where
     }
 }
 
-impl<B> PartialEq for Datum<B>
+impl<B, B2> PartialEq<Datum<B2>> for Datum<B>
 where
     B: Borrow<RawStr>,
+    B2: Borrow<RawStr>,
 {
-    fn eq(&self, other: &Self) -> bool {
+    fn eq(&self, other: &Datum<B2>) -> bool {
         match (self, other) {
-            (Self::Number(Some(l0)), Self::Number(Some(r0))) => {
+            (Self::Number(Some(l0)), Datum::Number(Some(r0))) => {
                 OrderedFloat(*l0) == OrderedFloat(*r0)
             }
-            (Self::Number(None), Self::Number(None)) => true,
-            (Self::String(l0), Self::String(r0)) => l0.borrow() == r0.borrow(),
+            (Self::Number(None), Datum::Number(None)) => true,
+            (Self::String(l0), Datum::String(r0)) => l0.borrow() == r0.borrow(),
             _ => false,
         }
     }
@@ -562,12 +563,23 @@ where
 
 impl<B> Eq for Datum<B> where B: Borrow<RawStr> {}
 
-impl<B> PartialOrd for Datum<B>
+impl<B, B2> PartialOrd<Datum<B2>> for Datum<B>
 where
     B: Borrow<RawStr>,
+    B2: Borrow<RawStr>,
 {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
+    fn partial_cmp(&self, other: &Datum<B2>) -> Option<Ordering> {
+        Some(match (self, other) {
+            (Self::Number(a), Datum::Number(b)) => match (a, b) {
+                (None, None) => Ordering::Equal,
+                (None, Some(_)) => Ordering::Less,
+                (Some(_), None) => Ordering::Greater,
+                (Some(a), Some(b)) => a.total_cmp(b),
+            },
+            (Self::Number(_), Datum::String(_)) => Ordering::Less,
+            (Self::String(_), Datum::Number(_)) => Ordering::Greater,
+            (Self::String(a), Datum::String(b)) => a.borrow().cmp(b.borrow()),
+        })
     }
 }
 
@@ -576,17 +588,7 @@ where
     B: Borrow<RawStr>,
 {
     fn cmp(&self, other: &Self) -> Ordering {
-        match (self, other) {
-            (Self::Number(a), Self::Number(b)) => match (a, b) {
-                (None, None) => Ordering::Equal,
-                (None, Some(_)) => Ordering::Less,
-                (Some(_), None) => Ordering::Greater,
-                (Some(a), Some(b)) => a.total_cmp(b),
-            },
-            (Self::Number(_), Self::String(_)) => Ordering::Less,
-            (Self::String(_), Self::Number(_)) => Ordering::Greater,
-            (Self::String(a), Self::String(b)) => a.borrow().cmp(b.borrow()),
-        }
+        self.partial_cmp(other).unwrap()
     }
 }
 
@@ -602,10 +604,7 @@ where
     }
 }
 
-impl<B> Datum<B>
-where
-    B: Borrow<RawStr>,
-{
+impl<B> Datum<B> {
     /// Constructs a new numerical [Datum] for the system-missing value.
     pub const fn sysmis() -> Self {
         Self::Number(None)
@@ -620,6 +619,19 @@ where
         }
     }
 
+    /// Returns the [VarType] corresponding to this datum.
+    pub fn var_type(&self) -> VarType {
+        match self {
+            Self::Number(_) => VarType::Numeric,
+            Self::String(_) => VarType::String,
+        }
+    }
+}
+
+impl<B> Datum<B>
+where
+    B: Borrow<RawStr>,
+{
     /// Returns the string inside this datum, or `None` if this is a numeric
     /// datum.
     pub fn as_string(&self) -> Option<&RawStr> {
@@ -643,14 +655,6 @@ where
         }
     }
 
-    /// Returns the [VarType] corresponding to this datum.
-    pub fn var_type(&self) -> VarType {
-        match self {
-            Self::Number(_) => VarType::Numeric,
-            Self::String(_) => VarType::String,
-        }
-    }
-
     /// Returns the [VarWidth] corresponding to this datum.
     pub fn width(&self) -> VarWidth {
         match self {
@@ -658,6 +662,19 @@ where
             Self::String(s) => VarWidth::String(s.borrow().len().try_into().unwrap()),
         }
     }
+
+    /// 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<B2>(&self, other: &Datum<B2>) -> bool
+    where
+        B2: Borrow<RawStr>,
+    {
+        match (self, other) {
+            (Self::String(a), Datum::String(b)) => a.borrow().eq_ignore_trailing_spaces(b.borrow()),
+            _ => self == other,
+        }
+    }
 }
 
 impl Datum<RawString> {
@@ -695,16 +712,6 @@ impl Datum<RawString> {
         }
     }
 
-    /// 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<B2>(&self, other: &Datum<RawString>) -> bool {
-        match (self, other) {
-            (Self::String(a), Self::String(b)) => a.eq_ignore_trailing_spaces(b),
-            _ => self == other,
-        }
-    }
-
     /// Removes trailing ASCII spaces from this datum, if it is a string.
     pub fn trim_end(&mut self) {
         match self {
index e423dc98cf6b77771b660cf79f44dccbe8128fcc..b3fb59a64d6781a135b13e05c9eae6807ff723e9 100644 (file)
@@ -920,7 +920,7 @@ mod test {
 
     use crate::{
         calendar::{days_in_month, is_leap_year},
-        data::{Datum, EncodedStr},
+        data::{Datum, EncodedStr, OwnedDatum},
         endian::Endian,
         format::{
             parse::{ParseError, ParseErrorKind, Sign},
@@ -1230,7 +1230,7 @@ mod test {
                     .with_settings(&settings)
                     .parse(&formatted)
                     .unwrap();
-                assert_eq!(parsed, Datum::Number(Some(expected as f64)));
+                assert_eq!(parsed, OwnedDatum::Number(Some(expected as f64)));
             }
         }
 
@@ -1608,8 +1608,8 @@ mod test {
                 assert_eq!(parsed, expected);
             }
         }
-        assert_eq!(parser.parse(".").unwrap(), Datum::Number(None));
-        assert_eq!(parser.parse("",).unwrap(), Datum::Number(None));
+        assert_eq!(parser.parse(".").unwrap(), OwnedDatum::Number(None));
+        assert_eq!(parser.parse("",).unwrap(), OwnedDatum::Number(None));
     }
 
     #[test]
@@ -1698,7 +1698,7 @@ mod test {
                 assert_eq!(parsed, number as f64, "formatted as {formatted:?}");
             }
         }
-        assert_eq!(parser.parse(".").unwrap(), Datum::Number(None));
+        assert_eq!(parser.parse(".").unwrap(), OwnedDatum::Number(None));
 
         let parser = Type::Z.parser(UTF_8).with_implied_decimals(1);
         for number in -999i32..=999 {