use crate::{
model::{
CachedEmoji, CachedGuild, CachedMember, CachedMessage, CachedPresence, CachedSticker,
CachedVoiceState,
},
GuildResource, InMemoryCache,
};
use dashmap::{iter::Iter, mapref::multiple::RefMulti};
use std::{hash::Hash, ops::Deref};
use twilight_model::{
channel::{Channel, StageInstance},
guild::{GuildIntegration, Role},
id::{
marker::{
ChannelMarker, EmojiMarker, GuildMarker, IntegrationMarker, MessageMarker, RoleMarker,
StageMarker, StickerMarker, UserMarker,
},
Id,
},
user::User,
};
pub struct IterReference<'a, K, V> {
inner: RefMulti<'a, K, V>,
}
impl<'a, K, V> IterReference<'a, K, V> {
const fn new(inner: RefMulti<'a, K, V>) -> Self {
Self { inner }
}
}
impl<K: Eq + Hash, V> IterReference<'_, K, V> {
pub fn key(&self) -> &K {
self.inner.key()
}
pub fn value(&self) -> &V {
self.inner.value()
}
}
impl<K: Eq + Hash, V> Deref for IterReference<'_, K, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
self.value()
}
}
#[derive(Debug)]
pub struct InMemoryCacheIter<'a>(&'a InMemoryCache);
impl<'a> InMemoryCacheIter<'a> {
pub(super) const fn new(cache: &'a InMemoryCache) -> Self {
Self(cache)
}
pub const fn cache_ref(&'a self) -> &'a InMemoryCache {
self.0
}
pub fn channels(&self) -> ResourceIter<'a, Id<ChannelMarker>, Channel> {
ResourceIter::new(self.0.channels.iter())
}
pub fn emojis(&self) -> ResourceIter<'a, Id<EmojiMarker>, GuildResource<CachedEmoji>> {
ResourceIter::new(self.0.emojis.iter())
}
pub fn guilds(&self) -> ResourceIter<'a, Id<GuildMarker>, CachedGuild> {
ResourceIter::new(self.0.guilds.iter())
}
pub fn integrations(
&self,
) -> ResourceIter<'a, (Id<GuildMarker>, Id<IntegrationMarker>), GuildResource<GuildIntegration>>
{
ResourceIter::new(self.0.integrations.iter())
}
pub fn members(&self) -> ResourceIter<'a, (Id<GuildMarker>, Id<UserMarker>), CachedMember> {
ResourceIter::new(self.0.members.iter())
}
pub fn messages(&self) -> ResourceIter<'a, Id<MessageMarker>, CachedMessage> {
ResourceIter::new(self.0.messages.iter())
}
pub fn presences(&self) -> ResourceIter<'a, (Id<GuildMarker>, Id<UserMarker>), CachedPresence> {
ResourceIter::new(self.0.presences.iter())
}
pub fn roles(&self) -> ResourceIter<'a, Id<RoleMarker>, GuildResource<Role>> {
ResourceIter::new(self.0.roles.iter())
}
pub fn stage_instances(
&self,
) -> ResourceIter<'a, Id<StageMarker>, GuildResource<StageInstance>> {
ResourceIter::new(self.0.stage_instances.iter())
}
pub fn stickers(&self) -> ResourceIter<'a, Id<StickerMarker>, GuildResource<CachedSticker>> {
ResourceIter::new(self.0.stickers.iter())
}
pub fn users(&self) -> ResourceIter<'a, Id<UserMarker>, User> {
ResourceIter::new(self.0.users.iter())
}
pub fn voice_states(
&self,
) -> ResourceIter<'a, (Id<GuildMarker>, Id<UserMarker>), CachedVoiceState> {
ResourceIter::new(self.0.voice_states.iter())
}
}
pub struct ResourceIter<'a, K, V> {
iter: Iter<'a, K, V>,
}
impl<'a, K, V> ResourceIter<'a, K, V> {
pub(super) const fn new(iter: Iter<'a, K, V>) -> Self {
Self { iter }
}
}
impl<'a, K: Eq + Hash, V> Iterator for ResourceIter<'a, K, V> {
type Item = IterReference<'a, K, V>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(IterReference::new)
}
}
#[cfg(test)]
mod tests {
use super::{InMemoryCacheIter, IterReference, ResourceIter};
use crate::{test, InMemoryCache};
use static_assertions::assert_impl_all;
use std::{borrow::Cow, fmt::Debug};
use twilight_model::{
id::{marker::UserMarker, Id},
user::User,
};
assert_impl_all!(InMemoryCacheIter<'_>: Debug, Send, Sync);
assert_impl_all!(IterReference<'_, Id<UserMarker>, User>: Send, Sync);
assert_impl_all!(ResourceIter<'_, Id<UserMarker>, User>: Iterator, Send, Sync);
#[test]
fn iter() {
let guild_id = Id::new(1);
let users = &[
(Id::new(2), Some(guild_id)),
(Id::new(3), Some(guild_id)),
(Id::new(4), None),
];
let cache = InMemoryCache::new();
for (user_id, maybe_guild_id) in users {
cache.cache_user(Cow::Owned(test::user(*user_id)), *maybe_guild_id);
}
let mut actual = cache.iter().users().map(|user| user.id).collect::<Vec<_>>();
actual.sort_unstable();
let expected = users.iter().map(|(id, _)| *id).collect::<Vec<_>>();
assert_eq!(actual, expected);
}
}