vaidcord 0.2.0

High-performance Discord framework: routers, middleware, resilient gateway and full voice transport
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::User;

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct Message {
    pub id: String,
    pub channel_id: String,
    #[serde(default)]
    pub guild_id: Option<String>,
    pub author: User,
    pub content: String,
    #[serde(default)]
    pub timestamp: Option<String>,
    #[serde(default)]
    pub edited_timestamp: Option<String>,
    #[serde(default)]
    pub tts: bool,
    #[serde(default)]
    pub mention_everyone: bool,
    #[serde(default)]
    pub mentions: Vec<User>,
    #[serde(default)]
    pub embeds: Vec<Value>,
    #[serde(default)]
    pub attachments: Vec<Value>,
    #[serde(default)]
    pub components: Vec<Value>,
    #[serde(default)]
    pub flags: Option<u64>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct EditedMessage {
    #[serde(flatten)]
    pub message: Message,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct DeletedMessage {
    pub id: String,
    pub channel_id: String,
    #[serde(default)]
    pub guild_id: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct BulkDeletedMessages {
    pub ids: Vec<String>,
    pub channel_id: String,
    #[serde(default)]
    pub guild_id: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct MessagePayload {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<String>,
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub tts: bool,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub embeds: Vec<Value>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub components: Vec<Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub allowed_mentions: Option<Value>,
}

impl MessagePayload {
    pub fn text(content: impl Into<String>) -> Self {
        Self {
            content: Some(content.into()),
            tts: false,
            embeds: Vec::new(),
            components: Vec::new(),
            allowed_mentions: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn message_payload_omits_empty_fields() {
        let payload = serde_json::to_value(MessagePayload::text("hello")).unwrap();

        assert_eq!(payload["content"], "hello");
        assert!(payload.get("embeds").is_none());
        assert!(payload.get("components").is_none());
    }

    #[test]
    fn decodes_typed_message() {
        let message: Message = serde_json::from_str(
            r#"{"id":"900","channel_id":"123","author":{"id":"42","username":"vaidcord"},"content":"pong"}"#,
        )
        .unwrap();

        assert_eq!(message.id, "900");
        assert_eq!(message.author.username, "vaidcord");
        assert_eq!(message.content, "pong");
    }
}