упр.03 задача 3
- Краен срок:
- 29.10.2025 23:59
- Точки:
- 2
Напиши програма, която дефинира тип Еvent, използвайки enum, който може да бъде една от следните разновидности:
Login { user: String, timestamp: u64 }Logout { user: String, timestamp: u64 }Purchase { user: String, item: String, amount: f64, timestamp: u64 }Error { code: i32, message: String, timestamp: u64 }
Освен това, дефинирай структура EventLog, която съдържа вектор от събития:
struct EventLog { events: Vec<Event>, }
- а) Добави асоциирана функция
fn new() -> EventLog, която създава празен лог. - б) Добави метод
fn add_event(&mut self, event: Event), който добавя събитието. - в) Добави метод
fn user_spent(&self, user: &str) -> f64, който връща общата сума, изхарчена от даден потребител. - г) Добави метод
fn summaries_by_type(&self) -> HashMap<String, usize>, който връща брой събития по тип. За ключ в речника използвайте низовете "Login", "Logout", "Purchase", "Error" - д) Добави функция
fn filter_events(&self, user: Option<&str>, after: Option<u64>) -> Vec<&Event>, която връща събития, отговарящи на зададените критерии чрез pattern matching.- Ако user е Some(u), върни само събития, свързани с този u (т.е. user трябва да съвпада с полето user в Login, Logout или Purchase). Error събития не трябва да се връщат.
- Ако after е Some(t), върни само събития с timestamp > t.
- Ако и двете са None, върни всички събития.
Задължително прочетете (или си припомнете): Указания за предаване на домашни
Погрижете се решението ви да се компилира с базовия тест:
// Include the solution source in the same file, so we
// don't have to worry about item visibility.
// Please don't use `include!` in real code, this is a hack
// around the checking system.
include!{ "../src/lib.rs" }
#[test]
fn test_empty() {
let log = EventLog::new();
assert_eq!(log.user_spent("Пешо"), 0.0);
assert_eq!(log.summaries_by_type(), HashMap::new());
assert!(matches!(log.filter_events(None, None).as_slice(), &[]));
assert!(matches!(log.filter_events(Some("Пешо"), None).as_slice(), &[]));
assert!(matches!(log.filter_events(None, Some(100)).as_slice(), &[]));
}
#[test]
fn test_basic() {
let mut log = EventLog::new();
let events = [
Event::Login {
user: "Пешо".to_string(),
timestamp: 123,
},
Event::Login {
user: "Тошо".to_string(),
timestamp: 125,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 130,
item: "мечка".to_string(),
amount: 11.0,
},
Event::Error {
code: 1404,
timestamp: 133,
message: "няма тюлени".to_string(),
},
Event::Logout {
user: "Тошо".to_string(),
timestamp: 135,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 140,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 141,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Logout {
user: "Пешо".to_string(),
timestamp: 143,
},
];
for evt in events {
log.add_event(evt);
}
assert_eq!(
log.summaries_by_type(),
[
("Login".to_string(), 2),
("Logout".to_string(), 2),
("Purchase".to_string(), 3),
("Error".to_string(), 1)
]
.into_iter()
.collect::<HashMap<_, _>>(),
);
assert_eq!(log.user_spent("Пешо"), 34.0);
assert_eq!(log.user_spent("Тошо"), 0.0);
assert_eq!(log.user_spent("Гошо"), 0.0);
{
let filtered = log.filter_events(Some("Пешо"), None);
let expected = &[
Event::Login {
user: "Пешо".to_string(),
timestamp: 123,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 130,
item: "мечка".to_string(),
amount: 11.0,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 140,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 141,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Logout {
user: "Пешо".to_string(),
timestamp: 143,
},
];
assert!(filtered.len() == expected.len() && std::iter::zip(&filtered, expected).all(|(a, b)| eq_event(a, b)));
}
{
let filtered = log.filter_events(None, Some(139));
let expected = &[
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 140,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Purchase {
user: "Пешо".to_string(),
timestamp: 141,
item: "мечка".to_string(),
amount: 11.5,
},
Event::Logout {
user: "Пешо".to_string(),
timestamp: 143,
},
];
assert!(filtered.len() == expected.len() && std::iter::zip(&filtered, expected).all(|(a, b)| eq_event(a, b)));
}
{
let filtered = log.filter_events(Some("Тошо"), Some(130));
let expected = &[
Event::Logout {
user: "Тошо".to_string(),
timestamp: 135,
},
];
assert!(filtered.len() == expected.len() && std::iter::zip(&filtered, expected).all(|(a, b)| eq_event(a, b)));
}
}
// Това можеше да се имплементира автоматично с `#[derive(Eq, PartialEq)]`,
// но забравихме да ви кажем в условието.
// Затова сега не можем да използваме `==` и `assert_eq` в тестовете.
fn eq_event(a: &Event, b: &Event) -> bool {
match (a, b) {
(
Event::Login {
user: user_a,
timestamp: ts_a,
},
Event::Login {
user: user_b,
timestamp: ts_b,
},
) => (user_a, ts_a) == (user_b, ts_b),
(
Event::Logout {
user: user_a,
timestamp: ts_a,
},
Event::Logout {
user: user_b,
timestamp: ts_b,
},
) => (user_a, ts_a) == (user_b, ts_b),
(
Event::Purchase {
user: user_a,
item: item_a,
amount: amount_a,
timestamp: ts_a,
},
Event::Purchase {
user: user_b,
item: item_b,
amount: amount_b,
timestamp: ts_b,
},
) => (user_a, item_a, amount_a, ts_a) == (user_b, item_b, amount_b, ts_b),
(
Event::Error {
code: code_a,
message: msg_a,
timestamp: ts_a,
},
Event::Error {
code: code_b,
message: msg_b,
timestamp: ts_b,
},
) => (code_a, msg_a, ts_a) == (code_b, msg_b, ts_b),
_ => false,
}
}
