use crate::{
contexts::fields::Message,
types::{chat, message},
};
use serde::{Deserialize, Serialize};
use std::{
collections::hash_map::{self, Entry, HashMap, IntoIter},
iter::FromIterator,
ops::Index,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)]
#[must_use]
pub struct MessageId {
pub chat_id: chat::Id,
pub message_id: message::Id,
}
impl MessageId {
pub fn from_context<C>(context: &C) -> Self
where
C: Message,
{
Self {
chat_id: context.chat().id,
message_id: context.message_id(),
}
}
pub const fn from_message(message: &message::Message) -> Self {
Self {
chat_id: message.chat.id,
message_id: message.id,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Messages<S> {
messages: HashMap<MessageId, S>,
}
impl<S> Messages<S> {
#[must_use]
pub fn new() -> Self {
Self {
messages: HashMap::new(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
messages: HashMap::with_capacity(capacity),
}
}
pub fn all_messages(&self) -> impl Iterator<Item = MessageId> + '_ {
self.messages.keys().copied()
}
pub fn messages_in_chat_by_id(
&self,
chat_id: chat::Id,
) -> impl Iterator<Item = message::Id> + '_ {
self.all_messages().filter_map(move |id| {
if id.chat_id == chat_id {
Some(id.message_id)
} else {
None
}
})
}
pub fn messages_in_chat<C>(
&self,
context: &C,
) -> impl Iterator<Item = message::Id> + '_
where
C: Message,
{
self.messages_in_chat_by_id(context.chat().id)
}
pub fn all_states(&self) -> impl Iterator<Item = &S> {
self.messages.values()
}
pub fn states_in_chat_by_id(
&self,
chat_id: chat::Id,
) -> impl Iterator<Item = &S> {
self.iter_in_chat_by_id(chat_id).map(|(_, state)| state)
}
pub fn states_in_chat<C>(&self, context: &C) -> impl Iterator<Item = &S>
where
C: Message,
{
self.states_in_chat_by_id(context.chat().id)
}
pub fn iter(&self) -> impl Iterator<Item = (MessageId, &S)> {
Iter(self.messages.iter())
}
pub fn iter_in_chat_by_id(
&self,
chat_id: chat::Id,
) -> impl Iterator<Item = (message::Id, &S)> {
self.iter().filter_map(move |(id, state)| {
if id.chat_id == chat_id {
Some((id.message_id, state))
} else {
None
}
})
}
pub fn iter_in_chat<C>(
&self,
context: &C,
) -> impl Iterator<Item = (message::Id, &S)>
where
C: Message,
{
self.iter_in_chat_by_id(context.chat().id)
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (MessageId, &mut S)> {
IterMut(self.messages.iter_mut())
}
pub fn iter_mut_in_chat_by_id(
&mut self,
chat_id: chat::Id,
) -> impl Iterator<Item = (message::Id, &mut S)> {
self.iter_mut().filter_map(move |(id, state)| {
if id.chat_id == chat_id {
Some((id.message_id, state))
} else {
None
}
})
}
pub fn iter_mut_in_chat<C>(
&mut self,
context: &C,
) -> impl Iterator<Item = (message::Id, &mut S)>
where
C: Message,
{
self.iter_mut_in_chat_by_id(context.chat().id)
}
pub fn into_iter_in_chat_by_id(
self,
chat_id: chat::Id,
) -> impl Iterator<Item = (message::Id, S)> {
self.into_iter().filter_map(move |(id, state)| {
if id.chat_id == chat_id {
Some((id.message_id, state))
} else {
None
}
})
}
pub fn into_iter_in_chat<C>(
self,
context: &C,
) -> impl Iterator<Item = (message::Id, S)>
where
C: Message,
{
self.into_iter_in_chat_by_id(context.chat().id)
}
#[must_use]
pub fn len(&self) -> usize {
self.messages.len()
}
#[must_use]
pub fn len_in_chat_by_id(&self, chat_id: chat::Id) -> usize {
self.iter_in_chat_by_id(chat_id).count()
}
#[must_use]
pub fn len_in_chat<C>(&self, context: &C) -> usize
where
C: Message,
{
self.iter_in_chat(context).count()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.messages.capacity()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.messages.is_empty()
}
#[must_use]
pub fn is_empty_in_chat_by_id(&self, chat_id: chat::Id) -> bool {
self.iter_in_chat_by_id(chat_id).next().is_none()
}
#[must_use]
pub fn is_empty_in_chat<C>(&self, context: &C) -> bool
where
C: Message,
{
self.is_empty_in_chat_by_id(context.chat().id)
}
#[must_use = "use `clear` if you don't need the iterator"]
pub fn drain(&mut self) -> impl Iterator<Item = (MessageId, S)> + '_ {
self.messages.drain()
}
pub fn clear(&mut self) {
self.messages.clear()
}
pub fn clear_in_chat_by_id(&mut self, chat_id: chat::Id) {
self.retain(|id, _| id.chat_id != chat_id);
}
pub fn clear_in_chat<C>(&mut self, context: &C)
where
C: Message,
{
self.clear_in_chat_by_id(context.chat().id);
}
pub fn reserve(&mut self, additional: usize) {
self.messages.reserve(additional)
}
pub fn shrink_to_fit(&mut self) {
self.messages.shrink_to_fit()
}
#[must_use]
pub fn get_by_id(&self, id: MessageId) -> Option<&S> {
self.messages.get(&id)
}
#[must_use]
pub fn get<C>(&self, context: &C) -> Option<&S>
where
C: Message,
{
self.get_by_id(MessageId::from_context(context))
}
#[must_use]
pub fn get_mut_by_id(&mut self, id: MessageId) -> Option<&mut S> {
self.messages.get_mut(&id)
}
#[must_use]
pub fn get_mut<C>(&mut self, context: &C) -> Option<&mut S>
where
C: Message,
{
self.get_mut_by_id(MessageId::from_context(context))
}
#[must_use]
pub fn entry_by_id(&mut self, id: MessageId) -> Entry<MessageId, S> {
self.messages.entry(id)
}
#[must_use]
pub fn entry<C>(&mut self, context: &C) -> Entry<MessageId, S>
where
C: Message,
{
self.entry_by_id(MessageId::from_context(context))
}
#[must_use]
pub fn has_by_id(&self, id: MessageId) -> bool {
self.messages.contains_key(&id)
}
#[must_use]
pub fn has<C>(&self, context: &C) -> bool
where
C: Message,
{
self.has_by_id(MessageId::from_context(context))
}
pub fn insert_by_id(&mut self, id: MessageId, value: S) -> Option<S> {
self.messages.insert(id, value)
}
pub fn insert<C>(&mut self, context: &C, value: S) -> Option<S>
where
C: Message,
{
self.insert_by_id(MessageId::from_context(context), value)
}
pub fn remove_by_id(&mut self, id: MessageId) -> Option<S> {
self.messages.remove(&id)
}
pub fn remove<C>(&mut self, context: &C) -> Option<S>
where
C: Message,
{
self.remove_by_id(MessageId::from_context(context))
}
pub fn retain<P>(&mut self, mut predicate: P)
where
P: FnMut(MessageId, &mut S) -> bool,
{
self.messages.retain(|&id, state| predicate(id, state))
}
}
impl<S> IntoIterator for Messages<S> {
type Item = (MessageId, S);
type IntoIter = IntoIter<MessageId, S>;
fn into_iter(self) -> Self::IntoIter {
self.messages.into_iter()
}
}
pub struct Iter<'a, S>(hash_map::Iter<'a, MessageId, S>);
impl<'a, S> Iterator for Iter<'a, S> {
type Item = (MessageId, &'a S);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(&id, state)| (id, state))
}
}
impl<'a, S> IntoIterator for &'a Messages<S> {
type Item = (MessageId, &'a S);
type IntoIter = Iter<'a, S>;
fn into_iter(self) -> Self::IntoIter {
Iter(self.messages.iter())
}
}
pub struct IterMut<'a, S>(hash_map::IterMut<'a, MessageId, S>);
impl<'a, S> Iterator for IterMut<'a, S> {
type Item = (MessageId, &'a mut S);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(&id, state)| (id, state))
}
}
impl<'a, S> IntoIterator for &'a mut Messages<S> {
type Item = (MessageId, &'a mut S);
type IntoIter = IterMut<'a, S>;
fn into_iter(self) -> Self::IntoIter {
IterMut(self.messages.iter_mut())
}
}
impl<S> Extend<(MessageId, S)> for Messages<S> {
fn extend<I: IntoIterator<Item = (MessageId, S)>>(&mut self, iterator: I) {
self.messages.extend(iterator)
}
}
impl<'a, S: Copy> Extend<(MessageId, &'a S)> for Messages<S> {
fn extend<I: IntoIterator<Item = (MessageId, &'a S)>>(
&mut self,
iterator: I,
) {
self.extend(iterator.into_iter().map(|(id, &state)| (id, state)))
}
}
impl<S> FromIterator<(MessageId, S)> for Messages<S> {
fn from_iter<I: IntoIterator<Item = (MessageId, S)>>(iter: I) -> Self {
Self {
messages: HashMap::from_iter(iter),
}
}
}
impl<S> Index<MessageId> for Messages<S> {
type Output = S;
fn index(&self, id: MessageId) -> &S {
self.messages.index(&id)
}
}
impl<S> Default for Messages<S> {
fn default() -> Self {
Self::new()
}
}