diff options
Diffstat (limited to 'src/args.rs')
-rw-r--r-- | src/args.rs | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/src/args.rs b/src/args.rs index 178203d..2a9bc28 100644 --- a/src/args.rs +++ b/src/args.rs @@ -9,9 +9,16 @@ use ::std::any::Any; use ::std::borrow::Cow; use ::std::future::Future; use ::std::io::Cursor; +use ::std::marker::PhantomData; +use ::std::num::ParseFloatError; +use ::std::num::ParseIntError; +use ::std::ops::RangeBounds; use ::std::pin::Pin; +use ::std::str::FromStr; -use crate::strcursor::{StringReader, ReadError}; +use crate::error::RangeError; +use crate::error::ReadError; +use crate::strcursor::StringReader; use crate::suggestion::Suggestions; use crate::suggestion::SuggestionsBuilder; @@ -34,7 +41,8 @@ pub struct CommandContext<'i, S, E>(::std::marker::PhantomData<(&'i str, S, E)>) /// use ::std::io::Cursor; /// /// use ::iosonism::args::ArgumentType; -/// use ::iosonism::strcursor::{ReadError, StringReader}; +/// use ::iosonism::error::ReadError; +/// use ::iosonism::strcursor::StringReader; /// /// struct BoolArgumentType; /// @@ -120,6 +128,7 @@ impl<T: ArgumentType<S, E>, S, E> ArgumentTypeAny<S, E> for T { /// A boolean argument. // FIXME add examples/expand docs // FIXME add tests +#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)] pub struct BoolArgumentType; /// An `ArgumentType` for `bool`. @@ -158,3 +167,85 @@ where for<'i> E: ReadError<'i, Cursor<&'i str>> Cow::Borrowed(&["true", "false"]) } } + +/// An integer argument. +#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash, Default)] +pub struct IntegerArgumentType<T, R: RangeBounds<T>> { + /// The valid range for this argument. + pub range: R, + /// PhantomData for the type. + pub _ty: PhantomData<T>, +} + +/// An `ArgumentType` for integer types. +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, +{ + /// An `IntegerArgumentType` parses an integer type. + type Result = T; + + /// Attempts to parse an integer from the `reader`. + fn parse<'i>( + &self, + reader: &mut Cursor<&'i str>, + ) -> Result<T, E> where E: 'i { + let start = reader.position(); + let value = reader.read_integer()?; + if self.range.contains(&value) { + Ok(value) + } else { + reader.set_position(start); + Err(E::value_not_in_range(reader, &value, &self.range)) + } + } + + /// Returns examples + fn get_examples(&self) -> Cow<'static, [&str]> { + Cow::Borrowed(&["0", "123", "-123"]) + } +} + +/// A float argument. +#[derive(Copy, Clone, PartialEq, Debug, PartialOrd, Default)] +pub struct FloatArgumentType<T, R: RangeBounds<T>> { + /// The valid range for this argument. + pub range: R, + /// PhantomData for the type. + pub _ty: PhantomData<T>, +} + +/// 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>, + T: PartialOrd<T> + FromStr<Err=ParseFloatError> + Any, +{ + /// A `FloatArgumentType` parses a float type. + type Result = T; + + /// Attempts to parse a float from the `reader`. + fn parse<'i>( + &self, + reader: &mut Cursor<&'i str>, + ) -> Result<T, E> where E: 'i { + let start = reader.position(); + let value = reader.read_float()?; + if self.range.contains(&value) { + Ok(value) + } else { + reader.set_position(start); + Err(E::value_not_in_range(reader, &value, &self.range)) + } + } + + /// Returns examples + fn get_examples(&self) -> Cow<'static, [&str]> { + Cow::Borrowed(&["0", "1.2", ".5", "-1", "-.5", "-1234.56"]) + } +} |