summary refs log tree commit diff stats
path: root/src/args.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/args.rs')
-rw-r--r--src/args.rs67
1 files changed, 53 insertions, 14 deletions
diff --git a/src/args.rs b/src/args.rs
index 5b9ce72..e7d76c3 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -10,6 +10,7 @@ use ::std::borrow::Cow;
 use ::std::fmt::Display;
 use ::std::fmt::Formatter;
 use ::std::future::Future;
+use ::std::hash::Hash;
 use ::std::io::Cursor;
 use ::std::marker::PhantomData;
 use ::std::num::ParseFloatError;
@@ -19,6 +20,9 @@ use ::std::ops::RangeBounds;
 use ::std::pin::Pin;
 use ::std::str::FromStr;
 
+use anycast::Anycast;
+//use ::ordered_float::OrderedFloat;
+
 use crate::error::RangeError;
 use crate::error::ReadError;
 use crate::strcursor::StringReader;
@@ -27,7 +31,7 @@ use crate::suggestion::SuggestionsBuilder;
 
 // FIXME delete when implemented
 /// The parsing context of a command.
-pub struct CommandContext<'i, S, E>(::std::marker::PhantomData<(&'i str, S, E)>);
+pub struct CommandContext<'i, S, E>(PhantomData<(&'i str, S, E)>);
 
 /// An argument parser/validator.
 ///
@@ -36,8 +40,8 @@ pub struct CommandContext<'i, S, E>(::std::marker::PhantomData<(&'i str, S, E)>)
 /// this trait. Nevertheless, Iosonism doesn't itself use threads, so a
 /// [workaround] can be used if one needs non-`Send + Sync` argument types.
 ///
-/// Additionally, argument types must be `Display`. This *is* reflected in this
-/// trait.
+/// Additionally, argument types must be `Display`, `Eq` and `Hash`. This *is*
+/// reflected in this trait.
 ///
 /// [workaround]: https://users.rust-lang.org/t/how-to-check-send-at-runtime-similar-to-how-refcell-checks-borrowing-at-runtime/68269
 ///
@@ -78,7 +82,7 @@ pub struct CommandContext<'i, S, E>(::std::marker::PhantomData<(&'i str, S, E)>)
 ///     }
 /// }
 /// ```
-pub trait ArgumentType<S, E>: Display {
+pub trait ArgumentType<S, E>: Display + Eq + ::std::hash::Hash {
     /// The parsed type of the argument.
     type Result: Sized + 'static + Any;
 
@@ -105,8 +109,8 @@ pub trait ArgumentType<S, E>: Display {
     }
 }
 
-/// Internal wrapper around `ArgumentType`, but with `Any`.
-pub(crate) trait ArgumentTypeAny<S, E>: Send + Sync + Display {
+/// Internal wrapper around `ArgumentType`, but with more `Any`.
+pub(crate) trait ArgumentTypeAny<S, E>: Send + Sync + Display + Anycast {
     /// Parses an argument of this type, returning the parsed argument.
     fn parse<'i>(
         &self,
@@ -122,11 +126,18 @@ pub(crate) trait ArgumentTypeAny<S, E>: Send + Sync + Display {
 
     /// Returns examples for this argument.
     fn get_examples(&self) -> Cow<'static, [&str]>;
+
+    /// Compares this `ArgumentType` with another.
+    fn dyn_eq(&self, other: &dyn ArgumentTypeAny<S, E>) -> bool;
+
+    /// Hashes this `ArgumentType`.
+    fn dyn_hash(&self, hasher: &mut dyn ::std::hash::Hasher);
 }
 
-/// Any `ArgumentType` that is also `Send` and `Sync` is an `ArgumentTypeAny`.
+/// Any `ArgumentType` that is also `Send`, `Sync`, `Eq` and `Hash` is an
+/// `ArgumentTypeAny`.
 impl<T, S, E> ArgumentTypeAny<S, E> for T
-where T: ArgumentType<S, E> + Send + Sync {
+where T: ArgumentType<S, E> + Send + Sync + Eq + ::std::hash::Hash + Any {
     fn parse<'i>(
         &self,
         reader: &mut Cursor<&'i str>,
@@ -145,6 +156,18 @@ where T: ArgumentType<S, E> + Send + Sync {
     fn get_examples(&self) -> Cow<'static, [&str]> {
         self.get_examples()
     }
+
+    fn dyn_eq(&self, other: &dyn ArgumentTypeAny<S, E>) -> bool {
+        match other.any_ref().downcast_ref() {
+            Some(other) => self == other,
+            None => false,
+        }
+    }
+
+    fn dyn_hash(&self, mut hasher: &mut dyn ::std::hash::Hasher) {
+        // rust-lang/rust#44015
+        self.hash(&mut hasher)
+    }
 }
 
 /// Any `dyn ArgumentTypeAny` (note the `dyn`!) is an `ArgumentType`.
@@ -171,6 +194,21 @@ impl<S, E> ArgumentType<S, E> for dyn ArgumentTypeAny<S, E> {
     }
 }
 
+impl<S, E> PartialEq for dyn ArgumentTypeAny<S, E> {
+    fn eq(&self, other: &Self) -> bool {
+        self.dyn_eq(other)
+    }
+}
+
+impl<S, E> Eq for dyn ArgumentTypeAny<S, E> {
+}
+
+impl<S, E> ::std::hash::Hash for dyn ArgumentTypeAny<S, E> {
+    fn hash<H: ::std::hash::Hasher>(&self, hasher: &mut H) {
+        self.dyn_hash(hasher as &mut dyn ::std::hash::Hasher)
+    }
+}
+
 /// A boolean argument.
 // FIXME add examples/expand docs
 #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)]
@@ -270,8 +308,8 @@ impl<S, E, T, R> ArgumentType<S, E> for IntegerArgumentType<T, R>
 where
     for<'i> E: ReadError<'i, Cursor<&'i str>>,
     for<'i> E: RangeError<'i, Cursor<&'i str>, T, R>,
-    R: RangeBounds<T>,
-    T: PartialOrd<T> + FromStr<Err=ParseIntError> + Any + Display,
+    R: RangeBounds<T> + Eq + Hash,
+    T: PartialOrd<T> + FromStr<Err=ParseIntError> + Any + Display + Eq + Hash,
 {
     /// An `IntegerArgumentType` parses an integer type.
     type Result = T;
@@ -299,8 +337,8 @@ where
 
 /// Formats this `IntegerArgumentType`.
 ///
-/// The resulting string follows the syntax `"integer(start,end)"`, with `start`
-/// and `end` being one of the below:
+/// The resulting string follows the syntax `"integer(start,end)"`, with
+/// `start` and `end` being one of the below:
 ///
 /// - `value` if the bound is inclusive.
 /// - `value*` if the bound is exclusive.
@@ -328,6 +366,7 @@ impl<T: Display, R: RangeBounds<T>> Display for IntegerArgumentType<T, R> {
     }
 }
 
+// FIXME implement Eq and Hash properly
 /// A float argument.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)]
 pub struct FloatArgumentType<T, R: RangeBounds<T>> {
@@ -376,8 +415,8 @@ impl<S, E, T, R> ArgumentType<S, E> for FloatArgumentType<T, R>
 where
     for<'i> E: ReadError<'i, Cursor<&'i str>>,
     for<'i> E: RangeError<'i, Cursor<&'i str>, T, R>,
-    R: RangeBounds<T>,
-    T: PartialOrd<T> + FromStr<Err=ParseFloatError> + Any + Display,
+    R: RangeBounds<T> + Eq + Hash,
+    T: PartialOrd<T> + FromStr<Err=ParseFloatError> + Any + Display + Eq + Hash,
 {
     /// A `FloatArgumentType` parses a float type.
     type Result = T;