summary refs log tree commit diff stats
path: root/src/args.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/args.rs')
-rw-r--r--src/args.rs73
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()
+    }
+}