refactor: generalize LruCache to support any key type (P5.16)
Made LruCache generic over key type K, not just UserId: - LruCache<V> → LruCache<K, V> - Added trait bounds: K: Eq + Hash + Clone + Copy - Updated UserCache field types: * user_usernames: LruCache<UserId, String> * user_names: LruCache<UserId, String> * user_statuses: LruCache<UserId, UserOnlineStatus> Benefits: - Reusable cache implementation for any key types - Type-safe caching - No additional dependencies Progress: Priority 5: 2/3 tasks, Total: 18/20 (90%) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
13
CONTEXT.md
13
CONTEXT.md
@@ -904,9 +904,9 @@ let message = MessageBuilder::new(MessageId::new(123))
|
||||
- ✅ Priority 2: 5/5 (100%)
|
||||
- ✅ Priority 3: 4/4 (100%) 🎉
|
||||
- ✅ Priority 4: 4/4 (100%) 🎉
|
||||
- ⏳ Priority 5: 1/3 (33%, P5.15 завершено)
|
||||
- ⏳ Priority 5: 2/3 (67%, P5.15, P5.16 завершены)
|
||||
|
||||
**Общий прогресс: 17/20 задач (85%)**
|
||||
**Общий прогресс: 18/20 задач (90%)**
|
||||
|
||||
**Последние изменения (1 февраля 2026)**:
|
||||
- ✅ **P5.15 — Feature flags для зависимостей** (2026-02-01)
|
||||
@@ -915,9 +915,14 @@ let message = MessageBuilder::new(MessageId::new(123))
|
||||
- Условная компиляция в коде с graceful degradation
|
||||
- Преимущества: уменьшение размера бинарника, модульность
|
||||
|
||||
- ✅ **P5.16 — LRU cache обобщение** (2026-02-01)
|
||||
- Обобщена структура `LruCache<K, V>` в src/tdlib/users.rs
|
||||
- Type-safe: `K: Eq + Hash + Clone + Copy`, `V: Clone`
|
||||
- Обновлены типы в UserCache: `LruCache<UserId, String>`, `LruCache<UserId, UserOnlineStatus>`
|
||||
- Переиспользуемая реализация без дополнительных зависимостей
|
||||
|
||||
**Следующие шаги**:
|
||||
- P5.16: LRU cache обобщение
|
||||
- P5.17: Tracing вместо println!
|
||||
- P5.17: Tracing вместо println! (последняя задача Priority 5!)
|
||||
|
||||
## Известные проблемы
|
||||
|
||||
|
||||
@@ -728,12 +728,28 @@ open = { version = "5.0", optional = true }
|
||||
|
||||
---
|
||||
|
||||
### 16. LRU cache обобщение
|
||||
### 16. LRU cache обобщение ✅ ЗАВЕРШЕНО
|
||||
|
||||
**Проблема**: Отдельные LRU кеши для `user_names` и `user_statuses`.
|
||||
|
||||
**Решение**: Создать обобщённый `LruCache<K, V>` или использовать готовый крейт `lru = "0.12"`.
|
||||
|
||||
**Реализовано**:
|
||||
- ✅ Обобщённая структура `LruCache<K, V>` в `src/tdlib/users.rs`
|
||||
- ✅ Type parameters:
|
||||
- `K: Eq + Hash + Clone + Copy` — тип ключа
|
||||
- `V: Clone` — тип значения
|
||||
- ✅ Обновлена `UserCache`:
|
||||
- `user_usernames: LruCache<UserId, String>`
|
||||
- `user_names: LruCache<UserId, String>`
|
||||
- `user_statuses: LruCache<UserId, UserOnlineStatus>`
|
||||
- ✅ Все методы обобщены: `get()`, `peek()`, `insert()`, `contains_key()`, `len()`
|
||||
|
||||
**Преимущества**:
|
||||
- ✅ Переиспользуемая реализация для любых типов ключей
|
||||
- ✅ Type-safe кеширование
|
||||
- ✅ Без дополнительных зависимостей
|
||||
|
||||
---
|
||||
|
||||
### 17. Tracing вместо println!
|
||||
@@ -781,10 +797,11 @@ tracing-subscriber = "0.3"
|
||||
- [x] P4.12 — Rustdoc ✅
|
||||
- [x] P4.13 — Config validation ✅
|
||||
- [x] P4.14 — Async/await consistency ✅
|
||||
- [ ] Priority 5: 1/3 задач
|
||||
- [ ] Priority 5: 2/3 задач
|
||||
- [x] P5.15 — Feature flags ✅
|
||||
- [x] P5.16 — LRU cache обобщение ✅
|
||||
|
||||
**Всего**: 17/20 задач (85%)
|
||||
**Всего**: 18/20 задач (90%)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,27 +13,32 @@ use super::types::UserOnlineStatus;
|
||||
///
|
||||
/// # Type Parameters
|
||||
///
|
||||
/// * `K` - Тип ключа (должен реализовывать `Eq + Hash + Clone + Copy`)
|
||||
/// * `V` - Тип значения (должен реализовывать `Clone`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut cache = LruCache::<String>::new(100);
|
||||
/// let mut cache = LruCache::<UserId, String>::new(100);
|
||||
/// cache.insert(UserId::new(1), "Alice".to_string());
|
||||
/// assert_eq!(cache.get(&UserId::new(1)), Some(&"Alice".to_string()));
|
||||
/// ```
|
||||
pub struct LruCache<V> {
|
||||
pub struct LruCache<K, V> {
|
||||
/// Хранилище ключ-значение.
|
||||
map: HashMap<UserId, V>,
|
||||
map: HashMap<K, V>,
|
||||
|
||||
/// Порядок доступа: последний элемент — самый недавно использованный.
|
||||
order: Vec<UserId>,
|
||||
order: Vec<K>,
|
||||
|
||||
/// Максимальная ёмкость кэша.
|
||||
capacity: usize,
|
||||
}
|
||||
|
||||
impl<V: Clone> LruCache<V> {
|
||||
impl<K, V> LruCache<K, V>
|
||||
where
|
||||
K: Eq + std::hash::Hash + Clone + Copy,
|
||||
V: Clone,
|
||||
{
|
||||
/// Создает новый LRU кэш с заданной ёмкостью.
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
@@ -44,7 +49,7 @@ impl<V: Clone> LruCache<V> {
|
||||
}
|
||||
|
||||
/// Получает значение и обновляет порядок доступа (помечает как использованное).
|
||||
pub fn get(&mut self, key: &UserId) -> Option<&V> {
|
||||
pub fn get(&mut self, key: &K) -> Option<&V> {
|
||||
if self.map.contains_key(key) {
|
||||
// Перемещаем ключ в конец (самый недавно использованный)
|
||||
self.order.retain(|k| k != key);
|
||||
@@ -56,12 +61,12 @@ impl<V: Clone> LruCache<V> {
|
||||
}
|
||||
|
||||
/// Получить значение без обновления порядка (для read-only доступа)
|
||||
pub fn peek(&self, key: &UserId) -> Option<&V> {
|
||||
pub fn peek(&self, key: &K) -> Option<&V> {
|
||||
self.map.get(key)
|
||||
}
|
||||
|
||||
/// Вставить значение
|
||||
pub fn insert(&mut self, key: UserId, value: V) {
|
||||
pub fn insert(&mut self, key: K, value: V) {
|
||||
if self.map.contains_key(&key) {
|
||||
// Обновляем существующее значение
|
||||
self.map.insert(key, value);
|
||||
@@ -81,7 +86,7 @@ impl<V: Clone> LruCache<V> {
|
||||
}
|
||||
|
||||
/// Проверить наличие ключа
|
||||
pub fn contains_key(&self, key: &UserId) -> bool {
|
||||
pub fn contains_key(&self, key: &K) -> bool {
|
||||
self.map.contains_key(key)
|
||||
}
|
||||
|
||||
@@ -118,10 +123,10 @@ impl<V: Clone> LruCache<V> {
|
||||
/// ```
|
||||
pub struct UserCache {
|
||||
/// LRU-кэш usernames: user_id → username.
|
||||
pub user_usernames: LruCache<String>,
|
||||
pub user_usernames: LruCache<UserId, String>,
|
||||
|
||||
/// LRU-кэш имён: user_id → display_name (first_name + last_name).
|
||||
pub user_names: LruCache<String>,
|
||||
pub user_names: LruCache<UserId, String>,
|
||||
|
||||
/// Связь chat_id → user_id для приватных чатов.
|
||||
pub chat_user_ids: HashMap<ChatId, UserId>,
|
||||
@@ -130,7 +135,7 @@ pub struct UserCache {
|
||||
pub pending_user_ids: Vec<UserId>,
|
||||
|
||||
/// LRU-кэш онлайн-статусов: user_id → status.
|
||||
pub user_statuses: LruCache<UserOnlineStatus>,
|
||||
pub user_statuses: LruCache<UserId, UserOnlineStatus>,
|
||||
|
||||
/// ID клиента TDLib для API вызовов.
|
||||
client_id: i32,
|
||||
|
||||
Reference in New Issue
Block a user