serenity/utils/argument_convert/
emoji.rs

1use std::fmt;
2
3use super::ArgumentConvert;
4use crate::model::prelude::*;
5use crate::prelude::*;
6
7/// Error that can be returned from [`Emoji::convert`].
8#[non_exhaustive]
9#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
10pub enum EmojiParseError {
11    /// Parser was invoked outside a guild.
12    OutsideGuild,
13    /// Guild was not in cache, or guild HTTP request failed.
14    FailedToRetrieveGuild,
15    /// The provided emoji string failed to parse, or the parsed result cannot be found in the
16    /// guild roles.
17    NotFoundOrMalformed,
18}
19
20impl std::error::Error for EmojiParseError {}
21
22impl fmt::Display for EmojiParseError {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::OutsideGuild => f.write_str("Tried to find emoji outside a guild"),
26            Self::FailedToRetrieveGuild => f.write_str("Could not retrieve guild data"),
27            Self::NotFoundOrMalformed => f.write_str("Emoji not found or unknown format"),
28        }
29    }
30}
31
32/// Look up a [`Emoji`].
33///
34/// Requires the cache feature to be enabled.
35///
36/// The lookup strategy is as follows (in order):
37/// 1. Lookup by ID.
38/// 2. [Lookup by extracting ID from the emoji](`crate::utils::parse_emoji`).
39/// 3. Lookup by name.
40#[async_trait::async_trait]
41impl ArgumentConvert for Emoji {
42    type Err = EmojiParseError;
43
44    async fn convert(
45        ctx: impl CacheHttp,
46        guild_id: Option<GuildId>,
47        _channel_id: Option<ChannelId>,
48        s: &str,
49    ) -> Result<Self, Self::Err> {
50        // Get Guild or PartialGuild
51        let guild_id = guild_id.ok_or(EmojiParseError::OutsideGuild)?;
52        let guild = guild_id
53            .to_partial_guild(&ctx)
54            .await
55            .map_err(|_| EmojiParseError::FailedToRetrieveGuild)?;
56
57        let direct_id = s.parse().ok();
58        let id_from_mention = crate::utils::parse_emoji(s).map(|e| e.id);
59
60        if let Some(emoji_id) = direct_id.or(id_from_mention) {
61            if let Some(emoji) = guild.emojis.get(&emoji_id).cloned() {
62                return Ok(emoji);
63            }
64        }
65
66        if let Some(emoji) =
67            guild.emojis.values().find(|emoji| emoji.name.eq_ignore_ascii_case(s)).cloned()
68        {
69            return Ok(emoji);
70        }
71
72        Err(EmojiParseError::NotFoundOrMalformed)
73    }
74}