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}