Решение на упр.09 задача 1 от Калоян Стоянов

Обратно към всички решения

Към профила на Калоян Стоянов

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 5 успешни тест(а)
  • 0 неуспешни тест(а)

Код

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
type Callback<S> = Box<dyn FnMut(&mut S) + Send>;
type CallbackMap<S> = HashMap<usize, Callback<S>>;
type EventCallbacksArc<S> = Arc<Mutex<EventCallbacks<S>>>;
type EventIdMapValue<S> = (String, EventCallbacksArc<S>);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Id {
event_id: usize,
callback_id: usize,
}
struct EventCallbacks<S> {
callbacks: CallbackMap<S>,
next_id: usize,
}
impl<S> EventCallbacks<S> {
fn new() -> Self {
EventCallbacks {
callbacks: HashMap::new(),
next_id: 0,
}
}
fn add_callback(&mut self, callback: Callback<S>) -> usize {
let id = self.next_id;
self.next_id += 1;
self.callbacks.insert(id, callback);
id
}
fn remove_callback(&mut self, callback_id: usize) -> Option<Callback<S>> {
self.callbacks.remove(&callback_id)
}
fn execute_callbacks(&mut self, state: &mut S) {
for callback in self.callbacks.values_mut() {
callback(state);
}
}
}
struct Inner<S> {
events: HashMap<String, EventCallbacksArc<S>>,
event_id_map: HashMap<Id, EventIdMapValue<S>>,
next_event_id: usize,
}
impl<S> Inner<S> {
fn new() -> Self {
Inner {
events: HashMap::new(),
event_id_map: HashMap::new(),
next_event_id: 0,
}
}
}
pub struct EventDispatcher<S> {
inner: Arc<Mutex<Inner<S>>>,
}
impl<S> EventDispatcher<S> {
pub fn new() -> Self {
EventDispatcher {
inner: Arc::new(Mutex::new(Inner::new())),
}
}
pub fn on(&self, event: &str, callback: Callback<S>) -> Id {
let mut inner = self.inner.lock().unwrap();
let event_callbacks = inner
.events
.entry(event.to_string())
.or_insert_with(|| Arc::new(Mutex::new(EventCallbacks::new())))
.clone();
let event_id = inner.next_event_id;
inner.next_event_id += 1;
let callback_id = {
let mut callbacks = event_callbacks.lock().unwrap();
callbacks.add_callback(callback)
};
let id = Id {
event_id,
callback_id,
};
inner
.event_id_map
.insert(id, (event.to_string(), event_callbacks));
id
}
pub fn off(&self, id: Id) -> Option<Callback<S>> {
let mut inner = self.inner.lock().unwrap();
if let Some((_event_name, event_callbacks)) = inner.event_id_map.remove(&id) {
drop(inner);
let mut callbacks = event_callbacks.lock().unwrap();
callbacks.remove_callback(id.callback_id)
} else {
None
}
}
pub fn emit(&self, event: &str, state: &mut S) {
let event_callbacks = {
let inner = self.inner.lock().unwrap();
inner.events.get(event).cloned()
};
if let Some(event_callbacks) = event_callbacks {
let mut callbacks = event_callbacks.lock().unwrap();
callbacks.execute_callbacks(state);
}
}
}
impl<S> Clone for EventDispatcher<S> {
fn clone(&self) -> Self {
EventDispatcher {
inner: Arc::clone(&self.inner),
}
}
}
impl<S> Default for EventDispatcher<S> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
#[test]
fn test_basic_event_dispatcher() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
let id = dispatcher.on("increment", Box::new(|s: &mut i32| *s += 1));
dispatcher.emit("increment", &mut state);
assert_eq!(state, 1);
dispatcher.emit("increment", &mut state);
assert_eq!(state, 2);
let callback = dispatcher.off(id);
assert!(callback.is_some());
dispatcher.emit("increment", &mut state);
assert_eq!(state, 2);
}
#[test]
fn test_multiple_callbacks() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
dispatcher.on("event", Box::new(|s: &mut i32| *s += 1));
dispatcher.on("event", Box::new(|s: &mut i32| *s += 10));
dispatcher.on("event", Box::new(|s: &mut i32| *s += 100));
dispatcher.emit("event", &mut state);
assert_eq!(state, 111);
}
#[test]
fn test_multithreaded() {
let dispatcher = EventDispatcher::new();
let mut handles = vec![];
for i in 0..5 {
let d = dispatcher.clone();
let handle = thread::spawn(move || {
d.on("test", Box::new(move |s: &mut i32| *s += i));
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let mut state = 0;
dispatcher.emit("test", &mut state);
assert_eq!(state, 0 + 1 + 2 + 3 + 4);
}
#[test]
fn test_different_events() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
dispatcher.on("add", Box::new(|s: &mut i32| *s += 5));
dispatcher.on("multiply", Box::new(|s: &mut i32| *s *= 2));
dispatcher.emit("add", &mut state);
assert_eq!(state, 5);
dispatcher.emit("multiply", &mut state);
assert_eq!(state, 10);
}
#[test]
fn test_callback_registers_another_callback() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
let d = dispatcher.clone();
dispatcher.on(
"foo",
Box::new(move |s: &mut i32| {
*s += 1;
d.on("bar", Box::new(|s: &mut i32| *s += 100));
}),
);
dispatcher.emit("foo", &mut state);
assert_eq!(state, 1);
dispatcher.emit("bar", &mut state);
assert_eq!(state, 101);
}
#[test]
fn test_callback_removes_another_callback() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
let id_bar = dispatcher.on("bar", Box::new(|s: &mut i32| *s += 50));
let d = dispatcher.clone();
dispatcher.on(
"foo",
Box::new(move |s: &mut i32| {
*s += 1;
d.off(id_bar);
}),
);
dispatcher.emit("foo", &mut state);
assert_eq!(state, 1);
dispatcher.emit("bar", &mut state);
assert_eq!(state, 1);
}
#[test]
fn test_nested_callback_modifications_no_deadlock() {
let dispatcher = EventDispatcher::new();
let mut state = Vec::new();
let d1 = dispatcher.clone();
let d2 = dispatcher.clone();
let d3 = dispatcher.clone();
dispatcher.on(
"event1",
Box::new(move |s: &mut Vec<i32>| {
s.push(1);
d1.on("event2", Box::new(|s: &mut Vec<i32>| s.push(2)));
}),
);
dispatcher.on(
"event2",
Box::new(move |s: &mut Vec<i32>| {
s.push(20);
d2.on("event3", Box::new(|s: &mut Vec<i32>| s.push(3)));
}),
);
dispatcher.on(
"event3",
Box::new(move |s: &mut Vec<i32>| {
s.push(30);
d3.on("event4", Box::new(|s: &mut Vec<i32>| s.push(4)));
}),
);
dispatcher.emit("event1", &mut state);
assert_eq!(state, vec![1]);
let initial_len = state.len();
dispatcher.emit("event2", &mut state);
assert_eq!(state.len(), initial_len + 2);
assert!(state.contains(&20));
assert!(state.contains(&2));
let initial_len = state.len();
dispatcher.emit("event3", &mut state);
assert_eq!(state.len(), initial_len + 2);
assert!(state.contains(&30));
assert!(state.contains(&3));
dispatcher.emit("event4", &mut state);
assert!(state.contains(&4));
}
#[test]
fn test_callback_modifies_same_event_different_callback() {
let dispatcher = EventDispatcher::new();
let mut state = 0;
let id1 = dispatcher.on("test", Box::new(|s: &mut i32| *s += 1));
let id2 = dispatcher.on("test", Box::new(|s: &mut i32| *s += 10));
let d = dispatcher.clone();
dispatcher.on(
"remover",
Box::new(move |_s: &mut i32| {
d.off(id1);
d.off(id2);
}),
);
dispatcher.emit("test", &mut state);
assert_eq!(state, 11);
dispatcher.emit("remover", &mut state);
dispatcher.emit("test", &mut state);
assert_eq!(state, 11);
}
}

Лог от изпълнението

Updating crates.io index
     Locking 17 packages to latest compatible versions
   Compiling proc-macro2 v1.0.103
   Compiling quote v1.0.42
   Compiling unicode-ident v1.0.22
   Compiling futures-core v0.3.31
   Compiling futures-sink v0.3.31
   Compiling futures-channel v0.3.31
   Compiling futures-task v0.3.31
   Compiling syn v2.0.111
   Compiling futures-io v0.3.31
   Compiling memchr v2.7.6
   Compiling slab v0.4.11
   Compiling pin-project-lite v0.2.16
   Compiling pin-utils v0.1.0
   Compiling solution v0.1.0 (/tmp/d20251211-1757769-15l37kl/solution)
   Compiling futures-macro v0.3.31
   Compiling futures-util v0.3.31
   Compiling futures-executor v0.3.31
   Compiling futures v0.3.31
    Finished `test` profile [unoptimized + debuginfo] target(s) in 9.26s
     Running tests/solution_test.rs (target/debug/deps/solution_test-ee0783488e12dce9)

running 13 tests
test solution_test::test_basic_run2 ... ok
test solution_test::test_basic_run1 ... ok
test solution_test::test_multithreaded_run1 ... ok
test solution_test::test_multithreaded_run2 ... ok
test solution_test::tests::test_basic_event_dispatcher ... ok
test solution_test::test_reentrant_run ... ok
test solution_test::tests::test_callback_registers_another_callback ... ok
test solution_test::tests::test_callback_modifies_same_event_different_callback ... ok
test solution_test::tests::test_callback_removes_another_callback ... ok
test solution_test::tests::test_different_events ... ok
test solution_test::tests::test_multiple_callbacks ... ok
test solution_test::tests::test_nested_callback_modifications_no_deadlock ... ok
test solution_test::tests::test_multithreaded ... ok

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

История (1 версия и 0 коментара)

Калоян качи първо решение на 10.12.2025 18:16 (преди около 2 месеца)