diff options
-rw-r--r-- | src/args.rs | 91 |
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. |