# Архитектурный проект на Rust: Проектирование автоматизированной системы заботы о питомцах (PetCare Hub)

> Итоговый архитектурный проект серии: проектируем многопоточную систему PetCare Hub. Объединяем RAII, Box, Arc/Mutex, Trait Objects, BinaryHeap, custom iterators и макросы.

- **URL:** https://eagle2000.space/rust/rust-pet-care-architecture/
- **Date:** 2026-08-09

- **Tags:** rust, dev, architecture, smart-feeder, traits, concurrency, collections

---
## Введение

Мы прошлись по фундаменту языка Rust: от управления памятью (RAII и `Box`), умных указателей (`Rc`, `Weak`, `Arc`) и внутренней мутабельности (`Cell`, `RefCell`, `Mutex`) до коллекций, итераторов и генераторов кода на макросах.

Настало время соединить все эти элементы в единый **практический архитектурный проект**!

Мы спроектируем систему **PetCare Hub** — автоматизированный комплекс управления заботой о питомцах (кошках, собаках, птицах). Система должна отслеживать состояние здоровья, управлять автоматическими кормушками и поилочками, обрабатывать датчики телеметрии в параллельных потоках и расставлять приоритеты экстренным вызовам ветеринара.

---

## 1. Доменная модель и гетерогенный полиморфизм

В реальном мире животные имеют разный рацион и правила ухода. В Rust мы описываем общее поведение через типаж `PetAction`. 

Так как мы не знаем заранее, сколько кошек или собак зарегистрирует пользователь, мы используем **динамическую диспетчеризацию (Trait Objects)** в виде `Box<dyn PetAction>`. Это обеспечивает гибкое хранение разного поведения в едином векторе без необходимости жесткого связывания типов на этапе компиляции.

А для быстрой регистрации новых карточек животных мы используем декларативный макрос `pet_profile!`.

Исследуйте доменную модель в интерактивных слайдах:


### 💻 Доменная модель и Trait Objects


#### Шаг 1

```rust
// Шаг 1: Доменная модель и полиморфизм через Trait Objects (dyn PetAction)
trait PetAction {
    fn name(&self) -> &str;
    fn perform_care(&self) -> String;
}

struct Cat {
    name: String,
}

impl PetAction for Cat {
    fn name(&self) -> &str { &self.name }
    fn perform_care(&self) -> String {
        format!("Кот {}: выдать порцию сухого корма и запустить автопоилку", self.name)
    }
}

struct Dog {
    name: String,
}

impl PetAction for Dog {
    fn name(&self) -> &str { &self.name }
    fn perform_care(&self) -> String {
        format!("Собака {}: выдать влажный корм и открыть умную дверцу в сад", self.name)
    }
}

fn main() {
    // Гетерогенная коллекция питомцев через Box<dyn PetAction>
    let pets: Vec<Box<dyn PetAction>> = vec![
        Box::new(Cat { name: "Барсик".to_string() }),
        Box::new(Dog { name: "Рекс".to_string() }),
    ];

    println!("--- Автоматический уход за питомцами ---");
    for pet in &pets {
        println!("{}", pet.perform_care());
    }
}
```

**1. Доменная модель и Trait Objects**
- Типаж `PetAction` описывает общий контракт поведения для всех питомцев.
- Обертка `Box<dyn PetAction>` позволяет хранить разные типы животных в одном векторе.


#### Шаг 2

```rust
// Шаг 2: Декларативный макрос регистратора питомцев pet_profile!
macro_rules! pet_profile {
    ( $name:expr, $species:expr, $weight:expr ) => {
        {
            format!("Карточка питомца: Кличка '{}' | Вид: {} | Вес: {} кг", $name, $species, $weight)
        }
    };
}

fn main() {
    let cat_info = pet_profile!("Люцифер", "Кот", 4.5);
    let parrot_info = pet_profile!("Кеша", "Попугай", 0.3);

    println!("{cat_info}");
    println!("{parrot_info}");
}
```

**2. Макрос быстрого создания профилей питомца**
- Макрос `pet_profile!` избавляет от дублирования кода при создании структуры метаданных.


---

## 2. Многопоточный хаб и Очередь Приоритетов

Фоновые потоки отслеживают показатели датчиков температуру и уровня воды. Чтобы безопасно делиться расписанием между потоками кормления и мониторинга, используется комбинация **`Arc<Mutex<Scheduler>>`**.

### Почему именно `BinaryHeap`?

В приюте или дома могут происходить события разной важности. Обычная очередь `VecDeque` обработала бы плановое кормление кота раньше, чем экстренный сигнал о повышенной температуре у собаки. 

Использование **`BinaryHeap` (Max-Кучи)** гарантирует, что задача с наивысшим приоритетом (например, `priority: 100` — выдача медикаментов) всегда будет обработана первой, независимо от того, когда она попала в очередь!

---

## 3. Фильтрация датчиков через Кастомный Итератор

Вместо выделения временных векторов в куче при поиске тревожных сигналов, мы пишем собственный итератор `CriticalAlertsIterator`. Он производит отбор критических ситуаций **лениво (Lazy Evaluation)** «на лету» во время обхода.

Запустите примеры многопоточной синхронизации и кастомного итератора:


### 💻 Многопоточность, Приоритеты и Итератор


#### Шаг 1

```rust
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::sync::{Arc, Mutex};
use std::thread;

// Элемент очереди ухода с приоритетом
#[derive(Eq, PartialEq)]
struct CareTask {
    priority: u32,
    description: String,
}

impl Ord for CareTask {
    fn cmp(&self, other: &Self) -> Ordering {
        self.priority.cmp(&other.priority) // Max-Heap по приоритету
    }
}

impl PartialOrd for CareTask {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn main() {
    // Многопоточный хаб управления приютом/кормушкой через Arc<Mutex>
    let schedule = Arc::new(Mutex::new(BinaryHeap::new()));

    // Фоновый поток добавляет регулярные кормления
    let sched_clone = Arc::clone(&schedule);
    let handle = thread::spawn(move || {
        let mut lock = sched_clone.lock().unwrap();
        lock.push(CareTask { priority: 10, description: "Плановое кормление в 18:00".to_string() });
    });

    // Главный поток регистрирует срочный прием лекарства
    {
        let mut lock = schedule.lock().unwrap();
        lock.push(CareTask { priority: 100, description: "СРОЧНО: Выдать инсулин коту Мурзику".to_string() });
    }

    handle.join().unwrap();

    println!("--- Выполнение задач ухода по степени важности ---");
    let mut lock = schedule.lock().unwrap();
    while let Some(task) = lock.pop() {
        println!("Выполняется [Приоритет {}]: {}", task.priority, task.description);
    }
}
```

**1. Многопоточный хаб и Очередь Приоритетов**
- `Arc<Mutex<...>>` обеспечивает безопасный доступ к планировщику из параллельных потоков.
- `BinaryHeap` гарантирует, что критические медицинские задачи (приоритет 100) выталкиваются раньше планового кормления.


#### Шаг 2

```rust
struct MedicalAlert {
    pet_name: String,
    is_critical: bool,
}

// Пользовательский итератор для фильтрации критических уведомлений
struct CriticalAlertsIterator<I> {
    inner: I,
}

impl<I: Iterator<Item = MedicalAlert>> Iterator for CriticalAlertsIterator<I> {
    type Item = MedicalAlert;

    fn next(&mut self) -> Option<Self::Item> {
        // Пропускаем некритические предупреждения лениво
        self.inner.find(|alert| alert.is_critical)
    }
}

fn main() {
    let alerts = vec![
        MedicalAlert { pet_name: "Шарик".to_string(), is_critical: false },
        MedicalAlert { pet_name: "Васька".to_string(), is_critical: true },
        MedicalAlert { pet_name: "Чижик".to_string(), is_critical: true },
    ];

    let critical_iter = CriticalAlertsIterator { inner: alerts.into_iter() };

    println!("--- Ленивая фильтрация экстренных сигналов ---");
    for alert in critical_iter {
        println!("ЭКСТРЕННЫЙ ВЫЗОВ ВЕТЕРИНАРА: Питомец {}", alert.pet_name);
    }
}
```

**2. Кастомный Итератор Экстренных Уведомлений**
- Реализация собственного типажа `Iterator` производит отбор критических элементов лениво во время обхода.


---

## Итоги серии: Архитектурные паттерны Rust

Проектируя PetCare Hub, мы увидели истинную силу Rust:

1. **Гарантии памяти без GC:** Умные указатели `Box` и `Arc` контролируют жизненный цикл объектов без паузы на сборку мусора.
2. **Безопасность потоков (Data Race Freedom):** Компилятор запретит передавать данные в потоки без реализации типажей `Send` и `Sync`.
3. **Нулевая стоимость абстракций:** Итераторы и макросы позволяют писать высокоуровневый код, который компилируется в максимально быстрый машинно-ориентированный код.

---

## Проверь свои знания!

Пройдите финальный тест по архитектурным решениям в Rust:


### 📝 Архитектура системы PetCare Hub в Rust


**1. Почему для хранения разнородных животных (кошек, собак, птиц) в одном векторе используется `Box<dyn PetAction>`?**

- [ ] Разные структуры имеют разный размер в памяти, а Box<dyn Trait> дает жирный указатель фиксированного размера с таблицей vtable
- [ ] Без указателя Box компилятор запрещает создавать структуры в Rust
- [ ] Box автоматизирует передачу данных по сети

**2. Какую роль выполняет связка `Arc<Mutex<...>>` в многопоточном хабе ухода за питомцами?**

- [ ] Arc разделяет владение между фоновыми потоками мониторинга, а Mutex гарантирует взаимное исключение при изменении состояния
- [ ] Arc выполняет автоматическую компрессию данных
- [ ] Mutex заменяет собой операционную систему

**3. Какая коллекция в Rust идеальна для очереди экстренных вызовов ветеринара и плановых кормлений?**

- [ ] BinaryHeap (Max-Куча)
- [ ] LinkedList
- [ ] Vec

**4. Какое ключевое преимущество дает использование пользовательского итератора для обработки телеметрии питомцев?**

- [ ] Обработка происходит лениво по одному элементу без создания промежуточных векторов в памяти
- [ ] Итератор автоматически переводит имена питомцев на русский язык
- [ ] Итераторы отменяют проверки заимствования

