roopes_core/patterns/observer/hash_subject.rs
1//! Contains types which allow [`Observer`]s
2//! (which implement the appropriate [`Hash`] and
3//! [`Eq`] traits) to be removed dynamically.
4
5use super::{
6 Observer,
7 Subject,
8};
9use crate::prelude::*;
10use std::{
11 borrow::BorrowMut,
12 cell::RefCell,
13 collections::HashSet,
14 hash::Hash,
15};
16
17/// Convenience type representing types which can
18/// be added and removed from the
19/// [`HashSetObserver`].
20pub trait HashSetObserver = Observer + Eq + Hash;
21
22/// Implements [`Subject`] backed by a
23/// [`HashSet<T>`]. `T` must implement
24/// [`PartialEq`] and [`Hash`].
25///
26/// # Examples
27/// ``` rust
28/// use roopes::prelude::*;
29/// use std::{
30/// cell::RefCell,
31/// rc::Rc,
32/// };
33/// use enclose::enclose;
34///
35/// let mut hs = observer::HashSubject::default();
36///
37/// let has_run = Rc::new(RefCell::new(false));
38/// let lc: ObservingCommand<_> = command::Hashable::new(
39/// command::Heap::from(enclose!((has_run) move || {
40/// (*has_run.borrow_mut()) = true;
41/// })),
42/// "Has Run").into();
43///
44/// hs.attach(lc);
45///
46/// assert!(!(*has_run.borrow()));
47/// hs.notify();
48/// assert!((*has_run.borrow()));
49/// ```
50pub struct HashSubject<O>
51where
52 O: HashSetObserver,
53{
54 listeners: HashSet<O>,
55}
56
57impl<O> Default for HashSubject<O>
58where
59 O: HashSetObserver,
60{
61 fn default() -> HashSubject<O>
62 {
63 Self::new(HashSet::default())
64 }
65}
66
67impl<O> HashSubject<O>
68where
69 O: HashSetObserver,
70{
71 /// Creates a new [`HashSubject`] with an
72 /// interior-mutable listener set.
73 /// [`HashSubject::default`] is probably
74 /// preferable in most situations.
75 #[must_use]
76 pub fn new(listeners: HashSet<O>) -> HashSubject<O>
77 {
78 HashSubject { listeners }
79 }
80}
81
82impl<O> AttachableSubject<O> for HashSubject<O>
83where
84 O: HashSetObserver,
85{
86 fn attach(
87 &mut self,
88 attach_observer: O,
89 )
90 {
91 self.listeners.borrow_mut().insert(attach_observer);
92 }
93}
94
95/// An Error which occurs during detachment.
96#[derive(Debug)]
97pub enum DetachError
98{
99 /// The specified observer couldn't be found.
100 ObserverNotFound,
101}
102
103impl<O> DetachableSubject<O, DetachError> for HashSubject<O>
104where
105 O: HashSetObserver,
106{
107 fn detach(
108 &mut self,
109 detach_observer: &O,
110 ) -> Result<(), DetachError>
111 {
112 if self.listeners.remove(detach_observer) {
113 Ok(())
114 } else {
115 Err(DetachError::ObserverNotFound)
116 }
117 }
118}
119
120impl<O> Subject for HashSubject<O>
121where
122 O: HashSetObserver,
123{
124 fn notify(&self)
125 {
126 self.listeners.iter().for_each(Observer::notify);
127 }
128}