aboutsummaryrefslogtreecommitdiff
path: root/src/framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/framework')
-rw-r--r--src/framework/standard/args.rs82
-rw-r--r--src/framework/standard/mod.rs2
2 files changed, 83 insertions, 1 deletions
diff --git a/src/framework/standard/args.rs b/src/framework/standard/args.rs
index d299b64..7fb82e4 100644
--- a/src/framework/standard/args.rs
+++ b/src/framework/standard/args.rs
@@ -101,6 +101,36 @@ impl Args {
.parse::<T>()?)
}
+ /// Like [`single`], but does "zero-copy" parsing.
+ ///
+ /// Refer to [`FromStrZc`]'s example on how to use this method.
+ ///
+ /// [`single`]: #method.single
+ /// [`FromStrZc`]: trait.FromStrZc.html
+ pub fn single_zc<'a, T: FromStrZc<'a> + 'a>(&'a mut self) -> Result<T, T::Err>
+ where T::Err: StdError {
+
+ // This is a hack as to mitigate some nasty lifetime errors.
+ //
+ // (Culprit `Vec::remove`s return type)
+ fn get_and_remove(b: &mut Vec<String>) -> Option<&str> {
+ struct GetThenRemove<'a>(&'a mut Vec<String>);
+
+ impl<'a> Drop for GetThenRemove<'a> {
+ fn drop(&mut self) {
+ if !self.0.is_empty() {
+ self.0.remove(0);
+ }
+ }
+ }
+
+ GetThenRemove(b).0.get(0).map(|s| s.as_str())
+ }
+
+ let a = get_and_remove(&mut self.delimiter_split).ok_or(Error::Eos)?;
+ Ok(FromStrZc::from_str(a)?)
+ }
+
/// Like [`single`], but doesn't remove the element.
///
/// # Examples
@@ -317,6 +347,58 @@ impl Args {
}
}
+/// A version of `FromStr` that allows for "zero-copy" parsing.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// use serenity::framework::standard::{Args, FromStrZc};
+/// use std::fmt;
+///
+/// struct NameDiscrim<'a>(&'a str, Option<&'a str>);
+///
+/// #[derive(Debug)]
+/// struct Error(&'static str);
+///
+/// impl std::error::Error for Error {
+/// fn description(&self) -> &str { self.0 }
+/// }
+///
+/// impl fmt::Display for Error {
+/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) }
+/// }
+///
+/// impl<'a> FromStrZc<'a> for NameDiscrim<'a> {
+/// type Err = Error;
+///
+/// fn from_str(s: &'a str) -> Result<NameDiscrim<'a>, Error> {
+/// let mut it = s.split("#");
+/// let name = it.next().ok_or(Error("name must be specified"))?;
+/// let discrim = it.next();
+/// Ok(NameDiscrim(name, discrim))
+/// }
+/// }
+///
+/// let mut args = Args::new("abc#1234", " ");
+/// let NameDiscrim(name, discrim) = args.single_zc::<NameDiscrim>().unwrap();
+///
+/// assert_eq!(name, "abc");
+/// assert_eq!(discrim, Some("1234"));
+/// ```
+pub trait FromStrZc<'a>: Sized {
+ type Err;
+
+ fn from_str(s: &'a str) -> ::std::result::Result<Self, Self::Err>;
+}
+
+impl<'a, T: FromStr> FromStrZc<'a> for T {
+ type Err = T::Err;
+
+ fn from_str(s: &'a str) -> ::std::result::Result<Self, Self::Err> {
+ <T as FromStr>::from_str(s)
+ }
+}
+
impl ::std::ops::Deref for Args {
type Target = [String];
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs
index 38c1d2d..947a885 100644
--- a/src/framework/standard/mod.rs
+++ b/src/framework/standard/mod.rs
@@ -14,7 +14,7 @@ pub use self::command::CommandOrAlias;
pub use self::configuration::Configuration;
pub use self::create_command::CreateCommand;
pub use self::create_group::CreateGroup;
-pub use self::args::{Args, Error as ArgError};
+pub use self::args::{Args, Iter, FromStrZc, Error as ArgError};
use self::command::{AfterHook, BeforeHook};
use std::collections::HashMap;