diff options
Diffstat (limited to 'src/framework')
| -rw-r--r-- | src/framework/standard/args.rs | 82 | ||||
| -rw-r--r-- | src/framework/standard/mod.rs | 2 |
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; |