use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::sync::{Mutex, OnceLock};
const MAX_TRACKED: usize = 512;
type Key = (i64, i32);
fn tracked() -> &'static Mutex<HashMap<Key, u64>> {
static TRACKED: OnceLock<Mutex<HashMap<Key, u64>>> = OnceLock::new();
TRACKED.get_or_init(|| Mutex::new(HashMap::new()))
}
pub(crate) fn fingerprint(body: &serde_json::Value) -> Option<(i64, i32, u64)> {
let chat_id = body.get("chat_id")?.as_i64()?;
let message_id = i32::try_from(body.get("message_id")?.as_i64()?).ok()?;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
body.get("rich_message")
.map(ToString::to_string)
.hash(&mut hasher);
body.get("reply_markup")
.map(ToString::to_string)
.hash(&mut hasher);
Some((chat_id, message_id, hasher.finish()))
}
pub(crate) fn is_redundant(chat_id: i64, message_id: i32, fingerprint: u64) -> bool {
tracked()
.lock()
.unwrap_or_else(|e| e.into_inner())
.get(&(chat_id, message_id))
== Some(&fingerprint)
}
pub(crate) fn remember(chat_id: i64, message_id: i32, fingerprint: u64) {
let mut map = tracked().lock().unwrap_or_else(|e| e.into_inner());
if map.len() >= MAX_TRACKED && !map.contains_key(&(chat_id, message_id)) {
map.clear();
}
map.insert((chat_id, message_id), fingerprint);
}
pub(crate) fn is_not_modified(description: &str) -> bool {
description.contains("message is not modified")
}
#[cfg(test)]
pub(crate) fn clear_for_test() {
tracked().lock().unwrap_or_else(|e| e.into_inner()).clear();
}