work
[pspp] / rust / src / identifier.rs
index 8727bf1ea360454bdc15a911dc7ec1a0cd563f49..d8b5219920b9958233d3f71e97304b0cbf72b4d5 100644 (file)
@@ -1,6 +1,11 @@
-use std::fmt::{Display, Formatter, Result as FmtResult};
-
-use encoding_rs::{EncoderResult, Encoding};
+use std::{
+    borrow::Borrow,
+    cmp::Ordering,
+    fmt::{Debug, Display, Formatter, Result as FmtResult},
+    hash::{Hash, Hasher},
+};
+
+use encoding_rs::{EncoderResult, Encoding, UTF_8};
 use finl_unicode::categories::{CharacterCategories, MajorCategory};
 use thiserror::Error as ThisError;
 use unicase::UniCase;
@@ -71,7 +76,7 @@ fn is_reserved_word(s: &str) -> bool {
     false
 }
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Identifier(pub UniCase<String>);
 
 impl Identifier {
@@ -79,6 +84,9 @@ impl Identifier {
     /// encoding used by the dictionary, not in UTF-8.
     pub const MAX_LEN: usize = 64;
 
+    pub fn new_utf8(s: &str) -> Result<Identifier, Error> {
+        Self::new(s, UTF_8)
+    }
     pub fn new(s: &str, encoding: &'static Encoding) -> Result<Identifier, Error> {
         Self::is_plausible(s)?;
         let (encoded, _, unencodable) = encoding.encode(s);
@@ -138,3 +146,85 @@ impl Display for Identifier {
         write!(f, "{}", self.0)
     }
 }
+
+pub trait HasIdentifier {
+    fn identifier(&self) -> &Identifier;
+}
+
+pub struct ByIdentifier<T>(pub T)
+where
+    T: HasIdentifier;
+
+impl<T> ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    pub fn new(inner: T) -> Self {
+        Self(inner)
+    }
+}
+
+impl<T> PartialEq for ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.0.identifier().eq(other.0.identifier())
+    }
+}
+
+impl<T> Eq for ByIdentifier<T> where T: HasIdentifier {}
+
+impl<T> PartialOrd for ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<T> Ord for ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.0.identifier().cmp(other.0.identifier())
+    }
+}
+
+impl<T> Hash for ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.identifier().hash(state)
+    }
+}
+
+impl<T> Borrow<Identifier> for ByIdentifier<T>
+where
+    T: HasIdentifier,
+{
+    fn borrow(&self) -> &Identifier {
+        self.0.identifier()
+    }
+}
+
+impl<T> Debug for ByIdentifier<T>
+where
+    T: HasIdentifier + Debug,
+{
+    fn fmt(&self, f: &mut Formatter) -> FmtResult {
+        self.0.fmt(f)
+    }
+}
+
+impl<T> Clone for ByIdentifier<T>
+where
+    T: HasIdentifier + Clone,
+{
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}