aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-09-19 09:00:03 -0700
committerAustin Hellyer <[email protected]>2016-10-18 11:14:27 -0700
commit8fc8c81403c3daa187ba96a7d488a64db21463bf (patch)
tree81bc4890c28b08ce806f69084617066bce863c2d /src/utils
downloadserenity-8fc8c81403c3daa187ba96a7d488a64db21463bf.tar.xz
serenity-8fc8c81403c3daa187ba96a7d488a64db21463bf.zip
Initial commit
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/colour.rs126
-rw-r--r--src/utils/message_builder.rs97
-rw-r--r--src/utils/mod.rs140
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))
+}