homework: use hash map and implement Debug trait

This commit is contained in:
7 changed files with 51 additions and 36 deletions

View File

@@ -75,8 +75,8 @@
- [x] Заменить паники на возврат Option в методах получения устройства по ключу. - [x] Заменить паники на возврат Option в методах получения устройства по ключу.
Доработать хранение объектов: Доработать хранение объектов:
- [ ] Заменить массивы устройств и комнат на ассоциативные коллекции из std. В качестве ключей использовать строки. - [x] Заменить массивы устройств и комнат на ассоциативные коллекции из std. В качестве ключей использовать строки.
- [ ] Реализовать трейт Debug на всех типах. - [x] Реализовать трейт Debug на всех типах.
- [ ] Добавить возможность динамически добавлять/удалять устройства в комнату. - [ ] Добавить возможность динамически добавлять/удалять устройства в комнату.
- [ ] Добавить возможность динамически добавлять/удалять комнату в дом. - [ ] Добавить возможность динамически добавлять/удалять комнату в дом.
- [ ] Добавить в тип умного дома метод, позволяющий сразу получить ссылку на умное устройство. Метод принимает имя комнаты - [ ] Добавить в тип умного дома метод, позволяющий сразу получить ссылку на умное устройство. Метод принимает имя комнаты

View File

@@ -1,5 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
#[derive(Debug)]
pub enum Device { pub enum Device {
Thermometer(super::Thermometer), Thermometer(super::Thermometer),
PowerSocket(super::PowerSocket), PowerSocket(super::PowerSocket),
@@ -20,6 +21,13 @@ impl Device {
pub fn print_status(&self) { pub fn print_status(&self) {
println!("{}", self.display()); println!("{}", self.display());
} }
pub fn get_name(&self) -> &str {
match self {
Device::Thermometer(thermometer) => thermometer.get_name(),
Device::PowerSocket(power_socket) => power_socket.get_name(),
}
}
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,35 +1,38 @@
use crate::Room; use crate::Room;
use std::collections::HashMap;
#[derive(Debug)]
pub struct House { pub struct House {
address: String, address: String,
rooms: Box<[Room]>, rooms: HashMap<String, Room>,
} }
impl House { impl House {
pub fn new(address: impl AsRef<str>, rooms: Box<[Room]>) -> Self { pub fn new(address: impl AsRef<str>, rooms: Box<[Room]>) -> Self {
let rooms = rooms.into_iter().map(|r| (r.get_name().to_string(), r)).collect();
Self { Self {
address: address.as_ref().to_string(), address: address.as_ref().to_string(),
rooms, rooms,
} }
} }
fn is_valid_idx(&self, idx: usize) -> bool { pub fn get_address(&self) -> &str {
idx < self.rooms.len() &self.address
} }
pub fn get_room(&self, idx: usize) -> Option<&Room> { pub fn get_room(&self, key: &str) -> Option<&Room> {
if self.is_valid_idx(idx) { Some(&self.rooms[idx]) } else { None } self.rooms.get(key)
} }
pub fn get_room_mut(&mut self, idx: usize) -> Option<&mut Room> { pub fn get_room_mut(&mut self, key: &str) -> Option<&mut Room> {
if self.is_valid_idx(idx) { Some(&mut self.rooms[idx]) } else { None } self.rooms.get_mut(key)
} }
pub fn print_status(&self) { pub fn print_status(&self) {
println!("HOUSE '{}':", self.address); println!("HOUSE '{}':", self.address);
println!("{}", "=".repeat(32)); println!("{}", "=".repeat(32));
for d in self.rooms.iter() { for (_, room) in self.rooms.iter() {
d.print_status(); room.print_status();
println!(); println!();
} }
} }
@@ -68,24 +71,28 @@ mod tests {
let mut house = create_test_house(); let mut house = create_test_house();
house.print_status(); house.print_status();
assert_eq!(house.address, "Best street, 777"); assert_eq!(house.address, "Best street, 777");
assert_eq!(house.get_address(), "Best street, 777");
assert_eq!(format!("{}", house.get_room(0).unwrap().get_device(0).unwrap().display()), "DEV:ThermA[ 20.0 ]");
assert_eq!( assert_eq!(
format!("{}", house.get_room(0).unwrap().get_device(1).unwrap().display()), format!("{}", house.get_room("main").unwrap().get_device("ThermA").unwrap().display()),
"DEV:ThermA[ 20.0 ]"
);
assert_eq!(
format!("{}", house.get_room("main").unwrap().get_device("PSocA").unwrap().display()),
"DEV:PSocA[ OFF : 0.0 ]" "DEV:PSocA[ OFF : 0.0 ]"
); );
assert_eq!( assert_eq!(
format!("{}", house.get_room(1).unwrap().get_device(0).unwrap().display()), format!("{}", house.get_room("bedroom").unwrap().get_device("PSocC").unwrap().display()),
"DEV:PSocC[ ON : 11.1 ]" "DEV:PSocC[ ON : 11.1 ]"
); );
let Device::PowerSocket(powers_socket) = house.get_room_mut(0).unwrap().get_device_mut(1).unwrap() else { let Device::PowerSocket(powers_socket) = house.get_room_mut("main").unwrap().get_device_mut("PSocA").unwrap() else {
unreachable!() unreachable!()
}; };
powers_socket.set_on(true); powers_socket.set_on(true);
assert_eq!( assert_eq!(
format!("{}", house.get_room(0).unwrap().get_device(1).unwrap().display()), format!("{}", house.get_room("main").unwrap().get_device("PSocA").unwrap().display()),
"DEV:PSocA[ ON : 12.3 ]" "DEV:PSocA[ ON : 12.3 ]"
); );
} }
@@ -93,6 +100,6 @@ mod tests {
#[test] #[test]
fn check_out_of_bounds() { fn check_out_of_bounds() {
let house = create_test_house(); let house = create_test_house();
assert!(house.get_room(2).is_none()); assert!(house.get_room("absent").is_none());
} }
} }

View File

@@ -32,7 +32,7 @@ fn main() {
house.print_status(); house.print_status();
print!("# Switching off a power socket in Hall... "); print!("# Switching off a power socket in Hall... ");
let Device::PowerSocket(power_socket) = house.get_room_mut(0).unwrap().get_device_mut(0).unwrap() else { let Device::PowerSocket(power_socket) = house.get_room_mut("Hall").unwrap().get_device_mut("PSocA").unwrap() else {
println!("FAILED!"); println!("FAILED!");
return; return;
}; };

View File

@@ -1,5 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
#[derive(Debug)]
pub struct PowerSocket { pub struct PowerSocket {
name: String, name: String,
power_rate: f32, power_rate: f32,

View File

@@ -1,12 +1,15 @@
use crate::Device; use crate::Device;
use std::collections::HashMap;
#[derive(Debug)]
pub struct Room { pub struct Room {
name: String, name: String,
devices: Box<[Device]>, devices: HashMap<String, Device>,
} }
impl Room { impl Room {
pub fn new(name: impl AsRef<str>, devices: Box<[Device]>) -> Self { pub fn new(name: impl AsRef<str>, devices: Box<[Device]>) -> Self {
let devices = devices.into_iter().map(|d| (d.get_name().to_string(), d)).collect();
Self { Self {
name: name.as_ref().to_string(), name: name.as_ref().to_string(),
devices, devices,
@@ -17,24 +20,19 @@ impl Room {
&self.name &self.name
} }
fn is_valid_idx(&self, idx: usize) -> bool { pub fn get_device(&self, key: &str) -> Option<&Device> {
idx < self.devices.len() self.devices.get(key)
} }
pub fn get_device(&self, idx: usize) -> Option<&Device> { pub fn get_device_mut(&mut self, key: &str) -> Option<&mut Device> {
if self.is_valid_idx(idx) { Some(&self.devices[idx]) } else { None } self.devices.get_mut(key)
}
pub fn get_device_mut(&mut self, idx: usize) -> Option<&mut Device> {
self.is_valid_idx(idx);
Some(&mut self.devices[idx])
} }
pub fn print_status(&self) { pub fn print_status(&self) {
println!("ROOM '{}':", self.name); println!("ROOM '{}':", self.name);
println!("{}", "-".repeat(24)); println!("{}", "-".repeat(24));
for d in self.devices.iter() { for (_, device) in self.devices.iter() {
d.print_status(); device.print_status();
} }
} }
} }
@@ -55,16 +53,16 @@ mod tests {
assert_eq!(room.get_name(), "test_room"); assert_eq!(room.get_name(), "test_room");
room.print_status(); room.print_status();
assert_eq!(format!("{}", room.get_device(0).unwrap().display()), "DEV:PSoc[ OFF : 0.0 ]"); assert_eq!(format!("{}", room.get_device("PSoc").unwrap().display()), "DEV:PSoc[ OFF : 0.0 ]");
assert_eq!(format!("{}", room.get_device(1).unwrap().display()), "DEV:Therm[ 21.6 ]"); assert_eq!(format!("{}", room.get_device("Therm").unwrap().display()), "DEV:Therm[ 21.6 ]");
let Device::PowerSocket(power_socket) = room.get_device_mut(0).unwrap() else { let Device::PowerSocket(power_socket) = room.get_device_mut("PSoc").unwrap() else {
unreachable!() unreachable!()
}; };
power_socket.set_on(true); power_socket.set_on(true);
assert_eq!(format!("{}", room.get_device(0).unwrap().display()), "DEV:PSoc[ ON : 12.3 ]"); assert_eq!(format!("{}", room.get_device("PSoc").unwrap().display()), "DEV:PSoc[ ON : 12.3 ]");
assert_eq!(format!("{}", room.get_device(1).unwrap().display()), "DEV:Therm[ 21.6 ]"); assert_eq!(format!("{}", room.get_device("Therm").unwrap().display()), "DEV:Therm[ 21.6 ]");
} }
#[test] #[test]
@@ -76,6 +74,6 @@ mod tests {
Device::Thermometer(Thermometer::new("Therm", 21.56)), Device::Thermometer(Thermometer::new("Therm", 21.56)),
]), ]),
); );
assert!(room.get_device(2).is_none()); assert!(room.get_device("dummy").is_none());
} }
} }

View File

@@ -1,5 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
#[derive(Debug)]
pub struct Thermometer { pub struct Thermometer {
name: String, name: String,
temperature: f32, temperature: f32,