From 784a3d79530ba3a9a18e31f98d7143315a71d86a Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Mon, 14 Feb 2022 14:39:17 -0300 Subject: Attempt to make trees --- src/args.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'src/args.rs') 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: Display { +pub trait ArgumentType: Display + Eq + ::std::hash::Hash { /// The parsed type of the argument. type Result: Sized + 'static + Any; @@ -105,8 +109,8 @@ pub trait ArgumentType: Display { } } -/// Internal wrapper around `ArgumentType`, but with `Any`. -pub(crate) trait ArgumentTypeAny: Send + Sync + Display { +/// Internal wrapper around `ArgumentType`, but with more `Any`. +pub(crate) trait ArgumentTypeAny: 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: 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) -> 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 ArgumentTypeAny for T -where T: ArgumentType + Send + Sync { +where T: ArgumentType + Send + Sync + Eq + ::std::hash::Hash + Any { fn parse<'i>( &self, reader: &mut Cursor<&'i str>, @@ -145,6 +156,18 @@ where T: ArgumentType + Send + Sync { fn get_examples(&self) -> Cow<'static, [&str]> { self.get_examples() } + + fn dyn_eq(&self, other: &dyn ArgumentTypeAny) -> 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 ArgumentType for dyn ArgumentTypeAny { } } +impl PartialEq for dyn ArgumentTypeAny { + fn eq(&self, other: &Self) -> bool { + self.dyn_eq(other) + } +} + +impl Eq for dyn ArgumentTypeAny { +} + +impl ::std::hash::Hash for dyn ArgumentTypeAny { + fn hash(&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 ArgumentType for IntegerArgumentType where for<'i> E: ReadError<'i, Cursor<&'i str>>, for<'i> E: RangeError<'i, Cursor<&'i str>, T, R>, - R: RangeBounds, - T: PartialOrd + FromStr + Any + Display, + R: RangeBounds + Eq + Hash, + T: PartialOrd + FromStr + 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> Display for IntegerArgumentType { } } +// FIXME implement Eq and Hash properly /// A float argument. #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)] pub struct FloatArgumentType> { @@ -376,8 +415,8 @@ impl ArgumentType for FloatArgumentType where for<'i> E: ReadError<'i, Cursor<&'i str>>, for<'i> E: RangeError<'i, Cursor<&'i str>, T, R>, - R: RangeBounds, - T: PartialOrd + FromStr + Any + Display, + R: RangeBounds + Eq + Hash, + T: PartialOrd + FromStr + Any + Display + Eq + Hash, { /// A `FloatArgumentType` parses a float type. type Result = T; -- cgit 1.4.1