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.rs91
1 files changed, 84 insertions, 7 deletions
diff --git a/src/args.rs b/src/args.rs
index e7d76c3..7e211ed 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -62,6 +62,7 @@ pub struct CommandContext<'i, S, E>(PhantomData<(&'i str, S, E)>);
 /// use ::iosonism::error::ReadError;
 /// use ::iosonism::strcursor::StringReader;
 ///
+/// #[derive(PartialEq, Eq, Hash)]
 /// struct BoolArgumentType;
 ///
 /// impl<S, E> ArgumentType<S, E> for BoolArgumentType
@@ -165,8 +166,10 @@ where T: ArgumentType<S, E> + Send + Sync + Eq + ::std::hash::Hash + Any {
     }
 
     fn dyn_hash(&self, mut hasher: &mut dyn ::std::hash::Hasher) {
+        // we do actually compare the typeid above, through downcast_ref!
+        self.type_id().hash(&mut hasher);
         // rust-lang/rust#44015
-        self.hash(&mut hasher)
+        self.hash(&mut hasher);
     }
 }
 
@@ -261,7 +264,7 @@ impl Display for BoolArgumentType {
 }
 
 /// An integer argument.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Default)]
 pub struct IntegerArgumentType<T, R: RangeBounds<T>> {
     /// The valid range for this argument.
     pub range: R,
@@ -366,9 +369,8 @@ 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)]
+#[derive(Copy, Clone, Debug, Default)]
 pub struct FloatArgumentType<T, R: RangeBounds<T>> {
     /// The valid range for this argument.
     pub range: R,
@@ -410,13 +412,88 @@ pub fn bounded_float<T, R: RangeBounds<T>>(
     }
 }
 
+/// Implement Eq and Hash for FloatArgumentType.
+macro_rules! impl_eq_hash {
+    ($t:ty) => {
+        impl<R: RangeBounds<$t>> PartialEq for FloatArgumentType<$t, R> {
+            fn eq(&self, other: &Self) -> bool {
+                use ::std::ops::Bound;
+                (match (self.range.start_bound(), other.range.start_bound()) {
+                    (Bound::Included(left), Bound::Included(right)) => {
+                        left.to_bits() == right.to_bits()
+                    },
+                    (Bound::Excluded(left), Bound::Excluded(right)) => {
+                        left.to_bits() == right.to_bits()
+                    },
+                    (Bound::Unbounded, Bound::Unbounded) => {
+                        true
+                    },
+                    _ => {
+                        false
+                    },
+                } && match (self.range.end_bound(), other.range.end_bound()) {
+                    (Bound::Included(left), Bound::Included(right)) => {
+                        left.to_bits() == right.to_bits()
+                    },
+                    (Bound::Excluded(left), Bound::Excluded(right)) => {
+                        left.to_bits() == right.to_bits()
+                    },
+                    (Bound::Unbounded, Bound::Unbounded) => {
+                        true
+                    },
+                    _ => {
+                        false
+                    },
+                })
+            }
+        }
+        impl<R: RangeBounds<$t>> Eq for FloatArgumentType<$t, R> {
+        }
+        impl<R: RangeBounds<$t>> Hash for FloatArgumentType<$t, R> {
+            fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
+                use ::std::ops::Bound;
+                match self.range.start_bound() {
+                    Bound::Included(f) => {
+                        0usize.hash(h);
+                        f.to_bits().hash(h);
+                    },
+                    Bound::Excluded(f) => {
+                        1usize.hash(h);
+                        f.to_bits().hash(h);
+                    },
+                    Bound::Unbounded => {
+                        2usize.hash(h);
+                    }
+                }
+                match self.range.end_bound() {
+                    Bound::Included(f) => {
+                        0usize.hash(h);
+                        f.to_bits().hash(h);
+                    },
+                    Bound::Excluded(f) => {
+                        1usize.hash(h);
+                        f.to_bits().hash(h);
+                    },
+                    Bound::Unbounded => {
+                        2usize.hash(h);
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl_eq_hash!(f32);
+impl_eq_hash!(f64);
+
 /// An `ArgumentType` for float types.
 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> + Eq + Hash,
-    T: PartialOrd<T> + FromStr<Err=ParseFloatError> + Any + Display + Eq + Hash,
+    R: RangeBounds<T>,
+    T: PartialOrd<T> + FromStr<Err=ParseFloatError> + Any + Display,
+    Self: Eq + Hash,
 {
     /// A `FloatArgumentType` parses a float type.
     type Result = T;
@@ -474,7 +551,7 @@ impl<T: Display, R: RangeBounds<T>> Display for FloatArgumentType<T, R> {
 }
 
 /// A string argument.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct StringArgumentType(StringMode);
 
 /// Creates a string argument that accepts simple words.