diff options
Diffstat (limited to 'src/args.rs')
-rw-r--r-- | src/args.rs | 67 |
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; |