diff options
| author | Austin Hellyer <[email protected]> | 2016-09-19 09:00:03 -0700 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-10-18 11:14:27 -0700 |
| commit | 8fc8c81403c3daa187ba96a7d488a64db21463bf (patch) | |
| tree | 81bc4890c28b08ce806f69084617066bce863c2d /src/utils | |
| download | serenity-8fc8c81403c3daa187ba96a7d488a64db21463bf.tar.xz serenity-8fc8c81403c3daa187ba96a7d488a64db21463bf.zip | |
Initial commit
Diffstat (limited to 'src/utils')
| -rw-r--r-- | src/utils/colour.rs | 126 | ||||
| -rw-r--r-- | src/utils/message_builder.rs | 97 | ||||
| -rw-r--r-- | src/utils/mod.rs | 140 |
3 files changed, 363 insertions, 0 deletions
diff --git a/src/utils/colour.rs b/src/utils/colour.rs new file mode 100644 index 0000000..7bb7bfd --- /dev/null +++ b/src/utils/colour.rs @@ -0,0 +1,126 @@ +use std::default::Default; + +macro_rules! colour { + ($struct_:ident; $($name:ident, $val:expr;)*) => { + impl $struct_ { + $( + pub fn $name() -> Colour { + Colour::new($val) + } + )* + } + } +} + +/// A utility struct to help with working with the basic representation of a +/// colour. This is particularly useful when working with a [`Role`]'s colour, +/// as the API works with an integer value instead of an RGB value. +/// +/// Instances can be created by using the struct's associated functions. These +/// produce values equivilant to those found in the official client's colour +/// picker. +/// +/// # Examples +/// +/// Passing in a role's colour, and then retrieving its green component +/// via [`get_g`]: +/// +/// ```rust,ignore +/// use serenity::utils::Colour; +/// +/// // assuming a `role` has already been bound +/// +/// let colour = Colour::new(role.colour); +/// let green = colour.get_g(); +/// +/// println!("The green component is: {}", green); +/// ``` +/// +/// Creating an instance with the [`dark_teal`] value: +/// +/// ```rust,ignore +/// use serenity::utils::Colour; +/// +/// let colour = Colour::dark_teal(); +/// ``` +/// +/// [`Role`]: ../model/struct.Role.html +/// [`dark_teal`]: #method.dark_teal +/// [`get_g`]: #method.get_g +pub struct Colour { + /// The raw inner integer value of this Colour. This is worked with to + /// generate values such as the red component value. + pub value: u32, +} + +impl Colour { + /// Generates a new Colour with the given integer value set. + pub fn new(value: u32) -> Colour { + Colour { + value: value, + } + } + + /// Returns the red RGB component of this Colour. + pub fn get_r(&self) -> u8 { + ((self.value >> 16) & 255) as u8 + } + + /// Returns the green RGB component of this Colour. + pub fn get_g(&self) -> u8 { + ((self.value >> 8) & 255) as u8 + } + + /// Returns the blue RGB component of this Colour. + pub fn get_b(&self) -> u8 { + (self.value & 255) as u8 + } + + /// Returns a tuple of the red, green, and blue components of this Colour. + pub fn get_tuple(&self) -> (u8, u8, u8) { + (self.get_r(), self.get_g(), self.get_b()) + } +} + +impl From<u32> for Colour { + fn from(value: u32) -> Colour { + Colour::new(value) + } +} + +impl From<u64> for Colour { + fn from(value: u64) -> Colour { + Colour::new(value as u32) + } +} + +colour! { + Colour; + blue, 0x3498db; + dark_blue, 0x206694; + dark_green, 0x1f8b4c; + dark_gold, 0xc27c0e; + dark_grey, 0x607d8b; + dark_magenta, 0xad1457; + dark_orange, 0xa84300; + dark_purple, 0x71368a; + dark_red, 0x992d22; + dark_teal, 0x11806a; + darker_grey, 0x546e7a; + gold, 0xf1c40f; + light_grey, 0x979c9f; + lighter_grey, 0x95a5a6; + magenta, 0xe91e63; + orange, 0xe67e22; + purple, 0x9b59b6; + red, 0xe74c3c; + teal, 0x1abc9c; +} + +impl Default for Colour { + fn default() -> Colour { + Colour { + value: 0, + } + } +} diff --git a/src/utils/message_builder.rs b/src/utils/message_builder.rs new file mode 100644 index 0000000..a24fd2d --- /dev/null +++ b/src/utils/message_builder.rs @@ -0,0 +1,97 @@ +use std::default::Default; +use std::fmt; +use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId}; + +/// The Message Builder is an ergonomic utility to easily build a message, +/// by adding text and mentioning mentionable structs. +/// +/// The finalized value can be accessed via `.build()` or the inner value. +/// +/// # Examples +/// +/// Build a message, mentioning a user and an emoji: +/// +/// ```rust,ignore +/// use serenity::utils::MessageBuilder; +/// +/// let content = MessageBuilder::new() +/// .push("You sent a message, ") +/// .mention(user) +/// .push("! "); +/// .mention(emoji) +/// .build(); +/// ``` +pub struct MessageBuilder(pub String); + +impl MessageBuilder { + /// Creates a new, empty-content builder. + pub fn new() -> MessageBuilder { + MessageBuilder::default() + } + + /// Pulls the inner value out of the builder. This is equivilant to simply + /// retrieving the value. + pub fn build(self) -> String { + self.0 + } + + /// Mentions the channel in the built message. + pub fn channel<C: Into<ChannelId>>(mut self, channel: C) -> Self { + self.0.push_str(&format!("{}", channel.into())); + + self + } + + /// Uses and displays the given emoji in the built message. + pub fn emoji(mut self, emoji: Emoji) -> Self { + self.0.push_str(&format!("{}", emoji)); + + self + } + + /// Mentions something that implements the + /// [Mentionable](../model/trait.Mentionable.html) trait. + pub fn mention<M: Mentionable>(mut self, item: M) -> Self { + self.0.push_str(&item.mention()); + + self + } + + /// Pushes a string to the internal message content. + /// + /// Note that this does not mutate either the given data or the internal + /// message content in anyway prior to appending the given content to the + /// internal message. + pub fn push(mut self, content: &str) -> Self { + self.0.push_str(content); + + self + } + + + /// Mentions the role in the built message. + pub fn role<R: Into<RoleId>>(mut self, role: R) -> Self { + self.0.push_str(&format!("{}", role.into())); + + self + } + + /// Mentions the user in the built message. + pub fn user<U: Into<UserId>>(mut self, user: U) -> Self { + self.0.push_str(&format!("{}", user.into())); + + self + } +} + +impl fmt::Display for MessageBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl Default for MessageBuilder { + fn default() -> MessageBuilder { + MessageBuilder(String::default()) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..a2dbf6f --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,140 @@ + +//! A set of utilities to help with common use cases that are not required to +//! fully use the library. + +use base64; +use std::ffi::OsStr; +use std::fs::File; +use std::io::Read; +use std::path::Path; +use ::prelude::*; + +mod colour; +mod message_builder; + +pub use self::colour::Colour; +pub use self::message_builder::MessageBuilder; + +macro_rules! cdn_concat { + ($e:expr) => { + concat!("https://cdn.discordapp.com", $e) + } +} +macro_rules! api { + ($e:expr) => { + concat!("https://discordapp.com/api/v6", $e) + }; + ($e:expr, $($rest:tt)*) => { + format!(api!($e), $($rest)*) + }; +} + +macro_rules! api_concat { + ($e:expr) => { + concat!("https://discordapp.com/api/v6", $e) + } +} +macro_rules! status_concat { + ($e:expr) => { + concat!("https://status.discordapp.com/api/v2", $e) + } +} + +#[doc(hidden)] +pub fn decode_array<T, F: Fn(Value) -> Result<T>>(value: Value, f: F) -> Result<Vec<T>> { + into_array(value).and_then(|x| x.into_iter().map(f).collect()) +} + +#[doc(hidden)] +pub fn into_array(value: Value) -> Result<Vec<Value>> { + match value { + Value::Array(v) => Ok(v), + value => Err(Error::Decode("Expected array", value)), + } +} + +macro_rules! request { + ($route:path, $method:ident($body:expr), $url:expr, $($rest:tt)*) => {{ + let client = HyperClient::new(); + try!(request($route, || client + .$method(&format!(api!($url), $($rest)*)) + .body(&$body))) + }}; + ($route:path, $method:ident($body:expr), $url:expr) => {{ + let client = HyperClient::new(); + try!(request($route, || client + .$method(api!($url)) + .body(&$body))) + }}; + ($route:path, $method:ident, $url:expr, $($rest:tt)*) => {{ + let client = HyperClient::new(); + try!(request($route, || client + .$method(&format!(api!($url), $($rest)*)))) + }}; + ($route:path, $method:ident, $url:expr) => {{ + let client = HyperClient::new(); + try!(request($route, || client + .$method(api_concat!($url)))) + }}; +} + +/// Retrieves the "code" part of an [invite][`RichInvite`] out of a URL. +/// +/// # Examples +/// Retrieving the code from the URL `https://discord.gg/0cDvIgU2voY8RSYL`: +/// +/// ```rust +/// use serenity::utils; +/// +/// assert!(utils::parse_invite("https://discord.gg/0cDvIgU2voY8RSYL") == "0cDvIgU2voY8RSYL"); +/// ``` +/// +/// [`RichInvite`]: ../model/struct.RichInvite.html +pub fn parse_invite(code: &str) -> &str { + if code.starts_with("https://discord.gg/") { + &code[19..] + } else if code.starts_with("http://discord.gg/") { + &code[18..] + } else if code.starts_with("discord.gg/") { + &code[11..] + } else { + code + } +} + +/// Reads an image from a path and encodes it into base64. +/// +/// This can be used for methods like [`EditProfile::avatar`]. +/// +/// # Examples +/// +/// Reads an image located at `./cat.png` into a base64-encoded string: +/// +/// ```rust,ignore +/// use serenity::utils; +/// +/// let image = match utils::read_image("./cat.png") { +/// Ok(image) => image, +/// Err(why) => { +/// // properly handle the error +/// }, +/// }; +/// ``` +/// +/// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar +pub fn read_image<P: AsRef<Path>>(path: P) -> Result<String> { + let path = path.as_ref(); + + let mut v = Vec::default(); + let mut f = try!(File::open(path)); + let _ = f.read_to_end(&mut v); + + let b64 = base64::encode(&v); + let ext = if path.extension() == Some(OsStr::new("png")) { + "png" + } else { + "jpg" + }; + + Ok(format!("data:image/{};base64,{}", ext, b64)) +} |