1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use super::Cache;

/// Trait used for updating the cache with a type.
///
/// This may be implemented on a type and used to update the cache via
/// [`Cache::update`].
///
/// # Examples
///
/// Creating a custom struct implementation to update the cache with:
///
/// ```rust
/// use serenity::{
///     cache::{Cache, CacheUpdate},
///     model::{
///         id::UserId,
///         user::User,
///     },
///     prelude::RwLock,
/// };
/// use std::{
///     collections::hash_map::Entry,
///     sync::Arc,
/// };
///
/// // For example, an update to the user's record in the database was
/// // published to a pubsub channel.
/// struct DatabaseUserUpdate {
///     user_avatar: Option<String>,
///     user_discriminator: u16,
///     user_id: UserId,
///     user_is_bot: bool,
///     user_name: String,
/// }
///
/// impl CacheUpdate for DatabaseUserUpdate {
///     // A copy of the old user's data, if it existed in the cache.
///     type Output = User;
///
///     fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
///         // If an entry for the user already exists, update its fields.
///         match cache.users.entry(self.user_id) {
///             Entry::Occupied(entry) => {
///                 let user = entry.get();
///                 let mut writer = user.write();
///                 let old = writer.clone();
///
///                 writer.bot = self.user_is_bot;
///                 writer.discriminator = self.user_discriminator;
///                 writer.id = self.user_id;
///
///                 if writer.avatar != self.user_avatar {
///                     writer.avatar = self.user_avatar.clone();
///                 }
///
///                 if writer.name != self.user_name {
///                     writer.name = self.user_name.clone();
///                 }
///
///                 // Return the old copy for the user's sake.
///                 Some(old)
///             },
///             Entry::Vacant(entry) => {
///                 entry.insert(Arc::new(RwLock::new(User {
///                     id: self.user_id,
///                     avatar: self.user_avatar.clone(),
///                     bot: self.user_is_bot,
///                     discriminator: self.user_discriminator,
///                     name: self.user_name.clone(),
///                 })));
///
///                 // There was no old copy, so return None.
///                 None
///             },
///         }
///     }
/// }
///
/// // Create an instance of the cache.
/// let mut cache = Cache::new();
///
/// // This is a sample pubsub message that you might receive from your
/// // database.
/// let mut update_message = DatabaseUserUpdate {
///     user_avatar: None,
///     user_discriminator: 6082,
///     user_id: UserId(379740138303127564),
///     user_is_bot: true,
///     user_name: "TofuBot".to_owned(),
/// };
///
/// // Update the cache with the message.
/// cache.update(&mut update_message);
/// ```
///
/// [`Cache::update`]: struct.Cache.html#method.update
pub trait CacheUpdate {
    /// The return type of an update.
    ///
    /// If there is nothing to return, specify this type as an unit (`()`).
    type Output;

    /// Updates the cache with the implementation.
    fn update(&mut self, &mut Cache) -> Option<Self::Output>;
}