aboutsummaryrefslogtreecommitdiff
path: root/src/cache
diff options
context:
space:
mode:
authorzeyla <[email protected]>2018-07-05 09:26:46 -0700
committerGitHub <[email protected]>2018-07-05 09:26:46 -0700
commit9e560628deb1cf66e0c5029f41a79404fadffb40 (patch)
tree83b28db08fd1c26fdfd577334252c2b6c618fcf7 /src/cache
parentMonomorphize all functions (diff)
downloadserenity-9e560628deb1cf66e0c5029f41a79404fadffb40.tar.xz
serenity-9e560628deb1cf66e0c5029f41a79404fadffb40.zip
Make the Cache Update API public (#344)
This commit makes the Cache Update API public, allowing users to manually update the cache, as well as implementing the caching API on their own types to work with mutating the cache. The motivation for this indirectly comes from a message cache: if a user has multiple processes that can receive cache updates (either splitting a bot's shards into multiple processes or other processes like web panels or pub/sub channels), then this will allow them to easily mutate the cache and feed all types implementing the CacheUpdate trait into `Cache::update`.
Diffstat (limited to 'src/cache')
-rw-r--r--src/cache/cache_update.rs100
-rw-r--r--src/cache/mod.rs22
2 files changed, 118 insertions, 4 deletions
diff --git a/src/cache/cache_update.rs b/src/cache/cache_update.rs
index a05cc3d..ba79727 100644
--- a/src/cache/cache_update.rs
+++ b/src/cache/cache_update.rs
@@ -1,7 +1,105 @@
use super::Cache;
-pub(crate) trait CacheUpdate {
+/// 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>;
}
diff --git a/src/cache/mod.rs b/src/cache/mod.rs
index e0a5ee6..3bf5a5a 100644
--- a/src/cache/mod.rs
+++ b/src/cache/mod.rs
@@ -56,7 +56,7 @@ use std::{
mod cache_update;
-pub(crate) use self::cache_update::*;
+pub use self::cache_update::CacheUpdate;
/// A cache of all events received over a [`Shard`], where storing at least
/// some data from the event is possible.
@@ -163,6 +163,12 @@ pub struct Cache {
}
impl Cache {
+ /// Creates a new cache.
+ #[inline]
+ pub fn new() -> Self {
+ Self::default()
+ }
+
/// Fetches the number of [`Member`]s that have not had data received.
///
/// The important detail to note here is that this is the number of
@@ -664,8 +670,18 @@ impl Cache {
self.categories.get(&channel_id).cloned()
}
- #[cfg(feature = "client")]
- pub(crate) fn update<E: CacheUpdate>(&mut self, e: &mut E) -> Option<E::Output> {
+ /// Updates the cache with the update implementation for an event or other
+ /// custom update implementation.
+ ///
+ /// Refer to the documentation for [`CacheUpdate`] for more information.
+ ///
+ /// # Examples
+ ///
+ /// Refer to the [`CacheUpdate` examples].
+ ///
+ /// [`CacheUpdate`]: trait.CacheUpdate.html
+ /// [`CacheUpdate` examples]: trait.CacheUpdate.html#examples
+ pub fn update<E: CacheUpdate>(&mut self, e: &mut E) -> Option<E::Output> {
e.update(self)
}