subscribers - done

This commit is contained in:
6 changed files with 75 additions and 5 deletions

View File

@@ -194,8 +194,8 @@
Добавить возможность добавления callback-ов в объект комнаты, которые срабатывают при добавлении новых устройств в комнату (паттерн Observer).
- [ ] Использовать динамический полиморфизм (трейт-объекты).
- [ ] Можно передавать как объект-subscriber, так и [замыкание](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=06e9dc9bcce297d1e80a22d7e9338ee8).
- [x] Использовать динамический полиморфизм (трейт-объекты).
- [x] Можно передавать как объект-subscriber, так и [замыкание](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=06e9dc9bcce297d1e80a22d7e9338ee8).
Добавить example-ы, демонстрирующие новый функционал.
@@ -205,3 +205,9 @@
- Приложение-пример успешно выполняется.
- Команды cargo clippy и cargo fmt --check не выводят ошибок и предупреждений.
- Присутствуют и успешно выполняются модульные тесты.
### Демонстационные примеры
- `src/bin/house_builder.rs` - билдер для умного дома
- `src/bin/reporter.rs` - компоновщик для построения отчета
- `src/bin/subscribers.rs` - добавление коллбеков в объект комнаты

View File

@@ -0,0 +1,22 @@
use smart_house::{Device, PowerSocket, Room, Subscriber};
fn main() {
let mut room = Room::default();
room.subscribe(MySubscriber::default());
room.subscribe(|dev: &Device| {
println!("device added: {}", dev.display());
});
room.insert_device("", PowerSocket::stub(12.0, false).into());
}
#[derive(Default)]
struct MySubscriber {}
impl Subscriber for MySubscriber {
fn on_event(&mut self, dev: &Device) {
println!("DEVICE ADDED: {}", dev.display());
}
}

View File

@@ -7,6 +7,7 @@ mod room;
mod builders;
mod print_status;
mod reporter;
mod subscriber;
mod thermometer;
pub use builders::{HouseBuilder, RoomBuilder};
@@ -17,4 +18,5 @@ pub use power_socket::PowerSocket;
pub use print_status::PrintStatus;
pub use reporter::Reporter;
pub use room::Room;
pub use subscriber::Subscriber;
pub use thermometer::Thermometer;

View File

@@ -1,15 +1,19 @@
use crate::{Device, PrintStatus};
use crate::{Device, PrintStatus, Subscriber};
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::io::Write;
#[derive(Debug)]
pub struct Room {
devices: HashMap<String, Device>,
subscribers: Vec<Box<dyn Subscriber>>,
}
impl Room {
pub fn new(devices: HashMap<String, Device>) -> Self {
Self { devices }
Self {
devices,
subscribers: Vec::new(),
}
}
pub fn get_device(&self, name: &str) -> Option<&Device> {
@@ -21,12 +25,19 @@ impl Room {
}
pub fn insert_device(&mut self, name: &str, device: Device) -> Option<Device> {
for subscriber in &mut self.subscribers {
subscriber.on_event(&device);
}
self.devices.insert(name.to_string(), device)
}
pub fn remove_device(&mut self, name: &str) -> Option<Device> {
self.devices.remove(name)
}
pub fn subscribe(&mut self, subscriber: impl Subscriber + 'static) {
self.subscribers.push(Box::new(subscriber));
}
}
impl PrintStatus for Room {
@@ -39,6 +50,21 @@ impl PrintStatus for Room {
}
}
impl Debug for Room {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Room")
.field("devices", &self.devices)
.field("subscribers.len()", &self.subscribers.len())
.finish()
}
}
impl Default for Room {
fn default() -> Self {
Room::new(HashMap::new())
}
}
#[macro_export]
macro_rules! room {
($($key:expr => $dev:expr),* $(,)?) => {

View File

@@ -0,0 +1,14 @@
use crate::Device;
pub trait Subscriber {
fn on_event(&mut self, device: &Device);
}
impl<F> Subscriber for F
where
F: Fn(&Device),
{
fn on_event(&mut self, value: &Device) {
self(value)
}
}