diff options
Diffstat (limited to 'src/args.rs')
-rw-r--r-- | src/args.rs | 73 |
1 files changed, 61 insertions, 12 deletions
diff --git a/src/args.rs b/src/args.rs index 7e84b48..2b8eecf 100644 --- a/src/args.rs +++ b/src/args.rs @@ -5,7 +5,9 @@ //! Argument processing. +use ::std::any::Any; use ::std::future::Future; +use ::std::io::Cursor; use ::std::pin::Pin; use crate::strcursor::StringReader; @@ -13,7 +15,8 @@ use crate::suggestion::Suggestions; use crate::suggestion::SuggestionsBuilder; // FIXME delete when implemented -pub struct CommandContext<'a, T>(::std::marker::PhantomData<(&'a str, T)>); +/// The parsing context of a command. +pub struct CommandContext<'i, S, E>(::std::marker::PhantomData<(&'i str, S, E)>); /// An argument parser. /// @@ -29,33 +32,39 @@ pub struct CommandContext<'a, T>(::std::marker::PhantomData<(&'a str, T)>); /// A very basic `bool` argument type: /// /// ``` +/// use ::std::io::Cursor; +/// /// use ::iosonism::args::ArgumentType; /// use ::iosonism::strcursor::{ReadError, StringReader}; /// /// struct BoolArgumentType; /// -/// impl<'i, R, S, E> ArgumentType<'i, R, S, E> for BoolArgumentType -/// where R: StringReader<'i>, E: ReadError<'i, R> { +/// impl<S, E> ArgumentType<S, E> for BoolArgumentType +/// where for<'i> E: ReadError<'i, Cursor<&'i str>> +/// { /// type Result = bool; -/// fn parse(&self, reader: &mut R) -> Result<bool, E> { +/// fn parse<'i>( +/// &self, +/// reader: &mut Cursor<&'i str>, +/// ) -> Result<bool, E> where E: 'i { /// reader.read_bool() /// } /// } /// ``` -pub trait ArgumentType<'i, R: StringReader<'i>, S, E> { +pub trait ArgumentType<S, E> { /// The parsed type of the argument. - type Result: Sized + 'static + ::std::any::Any; + type Result: Sized + 'static + Any; /// Parses an argument of this type, returning the parsed argument. - fn parse(&self, reader: &mut R) -> Result<Self::Result, E>; + fn parse<'i>( + &self, + reader: &mut Cursor<&'i str>, + ) -> Result<Self::Result, E> where E: 'i; /// Creates suggestions for this argument. - // The hope here is that S is lightweight enough for one to clone into the - // closure. Unfortunately making it borrowable would be a pain. - // FIXME: this API doesn't look great, can we make it better somehow? - fn list_suggestions( + fn list_suggestions<'i>( &self, - context: &CommandContext<'i, S>, + context: &CommandContext<'i, S, E>, builder: SuggestionsBuilder<'i>, ) -> Pin<Box<dyn Future<Output=Suggestions> + Send + 'i>> { let _ = context; @@ -68,3 +77,43 @@ pub trait ArgumentType<'i, R: StringReader<'i>, S, E> { Vec::new() } } + +/// Wrapper around `ArgumentType`, but with `Any`. +pub(crate) trait ArgumentTypeAny<S, E> { + /// Parses an argument of this type, returning the parsed argument. + fn parse<'i>( + &self, + reader: &mut Cursor<&'i str>, + ) -> Result<Box<dyn Any>, E> where E: 'i; + + /// Creates suggestions for this argument. + fn list_suggestions<'i>( + &self, + context: &CommandContext<'i, S, E>, + builder: SuggestionsBuilder<'i>, + ) -> Pin<Box<dyn Future<Output=Suggestions> + Send + 'i>>; + + /// Returns examples for this argument. + fn get_examples(&self) -> Vec<&str>; +} + +impl<T: ArgumentType<S, E>, S, E> ArgumentTypeAny<S, E> for T { + fn parse<'i>( + &self, + reader: &mut Cursor<&'i str>, + ) -> Result<Box<dyn Any>, E> where E: 'i { + self.parse(reader).map(|x| Box::new(x) as _) + } + + fn list_suggestions<'i>( + &self, + context: &CommandContext<'i, S, E>, + builder: SuggestionsBuilder<'i>, + ) -> Pin<Box<dyn Future<Output=Suggestions> + Send + 'i>> { + self.list_suggestions(context, builder) + } + + fn get_examples(&self) -> Vec<&str> { + self.get_examples() + } +} |