cpclib_bndbuild/
event.rs

1use std::cell::RefCell;
2use std::fmt::Debug;
3use std::ops::{Deref, DerefMut};
4use std::rc::Rc;
5use std::sync::{Arc, RwLock};
6use std::time::{Duration, Instant};
7
8use camino::Utf8Path;
9use cpclib_asm::EnvEventObserver;
10use cpclib_runner::event::EventObserver;
11
12use crate::task::Task;
13
14#[derive(Clone, Debug)]
15pub enum BndBuilderState<'a> {
16    ComputeDependencies(&'a Utf8Path),
17    RunTasks,
18    Finish
19}
20
21#[derive(Clone)]
22pub enum BndBuilderEvent<'a> {
23    ChangeState(BndBuilderState<'a>),
24    StartRule {
25        rule: &'a Utf8Path,
26        nb: usize,
27        out_of: usize
28    },
29    StopRule(&'a Utf8Path),
30    FailedRule(&'a Utf8Path),
31    StartTask(Option<&'a Utf8Path>, &'a Task),
32    StopTask(Option<&'a Utf8Path>, &'a Task, Duration),
33    TaskStdout(&'a Utf8Path, &'a Task, &'a str),
34    TaskStderr(&'a Utf8Path, &'a Task, &'a str),
35    Stdout(&'a str),
36    Stderr(&'a str)
37}
38
39pub trait BndBuilderObserver: EventObserver + EnvEventObserver {
40    fn update(&mut self, event: BndBuilderEvent);
41}
42
43impl<T: BndBuilderObserver> BndBuilderObserver for Box<T> {
44    fn update(&mut self, event: BndBuilderEvent) {
45        self.deref_mut().update(event)
46    }
47}
48
49impl<T: BndBuilderObserver> BndBuilderObserver for Arc<T> {
50    fn update(&mut self, event: BndBuilderEvent) {
51        Arc::<T>::get_mut(self).unwrap().update(event)
52    }
53}
54
55pub trait BndBuilderObserved: Debug + Sync + Send {
56    #[inline]
57    fn emit_stdout<S: AsRef<str>>(&self, s: S) {
58        self.notify(BndBuilderEvent::Stdout(s.as_ref()))
59    }
60    #[inline]
61    fn emit_stderr<S: AsRef<str>>(&self, s: S) {
62        self.notify(BndBuilderEvent::Stderr(s.as_ref()))
63    }
64    #[inline]
65    fn emit_task_stdout<S: AsRef<str>, P: AsRef<Utf8Path>>(&self, p: P, t: &Task, s: S) {
66        self.notify(BndBuilderEvent::TaskStdout(p.as_ref(), t, s.as_ref()))
67    }
68    #[inline]
69    fn emit_task_stderr<S: AsRef<str>, P: AsRef<Utf8Path>>(&self, p: P, t: &Task, s: S) {
70        self.notify(BndBuilderEvent::TaskStderr(p.as_ref(), t, s.as_ref()))
71    }
72    #[inline]
73    fn do_compute_dependencies<P: AsRef<Utf8Path>>(&self, p: P) {
74        self.notify(BndBuilderEvent::ChangeState(
75            BndBuilderState::ComputeDependencies(p.as_ref())
76        ))
77    }
78    #[inline]
79    fn do_run_tasks(&self) {
80        self.notify(BndBuilderEvent::ChangeState(BndBuilderState::RunTasks))
81    }
82    #[inline]
83    fn do_finish(&self) {
84        self.notify(BndBuilderEvent::ChangeState(BndBuilderState::Finish))
85    }
86    #[inline]
87    fn start_rule<P: AsRef<Utf8Path>>(&self, rule: P, nb: usize, out_of: usize) {
88        self.notify(BndBuilderEvent::StartRule {
89            rule: rule.as_ref(),
90            nb,
91            out_of
92        })
93    }
94    #[inline]
95    fn stop_rule<P: AsRef<Utf8Path>>(&self, task: P) {
96        self.notify(BndBuilderEvent::StopRule(task.as_ref()))
97    }
98    #[inline]
99    fn failed_rule<P: AsRef<Utf8Path>>(&self, task: P) {
100        self.notify(BndBuilderEvent::FailedRule(task.as_ref()))
101    }
102    #[inline]
103    fn start_task(&self, rule: Option<&Utf8Path>, task: &Task) {
104        self.notify(BndBuilderEvent::StartTask(rule, task))
105    }
106    #[inline]
107    fn stop_task(&self, rule: Option<&Utf8Path>, task: &Task, duration: Duration) {
108        self.notify(BndBuilderEvent::StopTask(rule, task, duration))
109    }
110    #[inline]
111    fn notify(&self, event: BndBuilderEvent<'_>) {
112        let observers = self.observers().clone();
113        for observer in observers.iter() {
114            observer.update(event.clone());
115        }
116    }
117    fn observers(&self) -> Arc<ListOfBndBuilderObserverRc>;
118    fn add_observer(&mut self, observer: BndBuilderObserverRc);
119}
120
121#[derive(Debug, Clone)]
122pub struct BndBuilderObserverRc(pub(crate) Arc<RwLock<dyn BndBuilderObserver + Sync + Send>>);
123#[derive(Clone, Debug)]
124pub struct ListOfBndBuilderObserverRc(Vec<BndBuilderObserverRc>);
125
126impl BndBuilderObserverRc {
127    pub fn new<O: BndBuilderObserver + Sized + 'static + Sync + Send>(observer: O) -> Self {
128        let observer = RwLock::new(observer);
129        let observer = Arc::new(observer);
130        Self(observer)
131    }
132
133    pub fn new_default() -> Self {
134        let observer = BndBuilderDefaultObserver::default();
135        Self::new(observer)
136    }
137
138    pub fn update(&self, event: BndBuilderEvent) {
139        self.0.deref().write().unwrap().deref_mut().update(event);
140    }
141}
142
143impl ListOfBndBuilderObserverRc {
144    pub fn iter(&self) -> ListOfBndBuilderObserverRcIter {
145        ListOfBndBuilderObserverRcIter { list: self, idx: 0 }
146    }
147
148    pub fn add_observer(&mut self, o: BndBuilderObserverRc) {
149        self.0.push(o);
150    }
151}
152
153pub struct ListOfBndBuilderObserverRcIter<'l> {
154    list: &'l ListOfBndBuilderObserverRc,
155    idx: usize
156}
157
158impl Iterator for ListOfBndBuilderObserverRcIter<'_> {
159    type Item = BndBuilderObserverRc;
160
161    fn next(&mut self) -> Option<Self::Item> {
162        let vec = self.list.0.deref();
163        if self.idx == vec.len() {
164            None
165        }
166        else {
167            let res = vec.get(self.idx).cloned();
168            self.idx += 1;
169            res
170        }
171    }
172}
173
174impl Deref for BndBuilderObserverRc {
175    type Target = Arc<RwLock<dyn BndBuilderObserver + Sync + Send>>;
176
177    fn deref(&self) -> &Self::Target {
178        &self.0
179    }
180}
181
182impl DerefMut for BndBuilderObserverRc {
183    fn deref_mut(&mut self) -> &mut Self::Target {
184        &mut self.0
185    }
186}
187
188impl From<Vec<BndBuilderObserverRc>> for ListOfBndBuilderObserverRc {
189    fn from(value: Vec<BndBuilderObserverRc>) -> Self {
190        Self(value)
191    }
192}
193
194impl Deref for ListOfBndBuilderObserverRc {
195    type Target = Vec<BndBuilderObserverRc>;
196
197    fn deref(&self) -> &Self::Target {
198        &self.0
199    }
200}
201
202impl DerefMut for ListOfBndBuilderObserverRc {
203    fn deref_mut(&mut self) -> &mut Self::Target {
204        &mut self.0
205    }
206}
207
208impl Default for ListOfBndBuilderObserverRc {
209    fn default() -> Self {
210        Self(Vec::with_capacity(1))
211    }
212}
213
214impl EventObserver for ListOfBndBuilderObserverRc {
215    fn emit_stdout(&self, s: &str) {
216        for observer in self.0.clone().into_iter() {
217            observer.0.deref().read().unwrap().emit_stdout(s);
218        }
219    }
220
221    fn emit_stderr(&self, s: &str) {
222        for observer in self.0.clone().into_iter() {
223            observer.0.deref().read().unwrap().emit_stderr(s);
224        }
225    }
226}
227
228impl BndBuilderObserver for ListOfBndBuilderObserverRc {
229    fn update(&mut self, event: BndBuilderEvent) {
230        for observer in self.0.clone().into_iter() {
231            let mut observer = observer.0.deref().write().unwrap();
232            observer.update(event.clone());
233        }
234    }
235}
236
237#[derive(Debug, Clone)]
238pub struct RuleTaskEventDispatcher<'observed, 'rule, 'task, E>
239where E: BndBuilderObserved
240{
241    observed: &'observed E,
242    rule: Option<&'rule Utf8Path>,
243    task: &'task Task,
244    start: std::time::Instant
245}
246
247// impl<'observed, 'rule, 'task, E: BndBuilderObserved> Into<ListOfBndBuilderObserverRc> for RuleTaskEventDispatcher<'observed, 'rule, 'task, E>
248// where E: BndBuilderObserved
249// {
250// fn into(self) -> ListOfBndBuilderObserverRc {
251// let mut list = ListOfBndBuilderObserverRc::default();
252// list.add_observer(self.into());
253// list
254// }
255// }
256
257// impl<'observed, 'rule, 'task, E: BndBuilderObserved> Into<BndBuilderObserverRc> for RuleTaskEventDispatcher<'observed, 'rule, 'task, E>
258// where E: BndBuilderObserved
259// {
260// fn into(self) -> BndBuilderObserverRc {
261// BndBuilderObserverRc(Rc::new(RefCell::new(Box::new(self.clone()))))
262// }
263// }
264
265impl<E> Drop for RuleTaskEventDispatcher<'_, '_, '_, E>
266where E: BndBuilderObserved
267{
268    fn drop(&mut self) {
269        self.observed
270            .stop_task(self.rule, self.task, std::time::Instant::now() - self.start);
271    }
272}
273
274impl<'observed, 'rule, 'task, E> RuleTaskEventDispatcher<'observed, 'rule, 'task, E>
275where E: BndBuilderObserved
276{
277    #[inline]
278    pub fn new(builder: &'observed E, rule: &'rule Utf8Path, task: &'task Task) -> Self {
279        builder.start_task(Some(rule), task);
280        Self {
281            observed: builder,
282            rule: Some(rule),
283            task,
284            start: Instant::now()
285        }
286    }
287
288    #[inline]
289    pub fn new_alone(observed: &'observed E, task: &'task Task) -> Self {
290        observed.start_task(None, task);
291        Self {
292            observed,
293            rule: None,
294            task,
295            start: Instant::now()
296        }
297    }
298}
299
300impl<E> EventObserver for RuleTaskEventDispatcher<'_, '_, '_, E>
301where E: BndBuilderObserved + Sync
302{
303    #[inline]
304    fn emit_stdout(&self, s: &str) {
305        match self.rule {
306            Some(rule) => self.observed.emit_task_stdout(rule, self.task, s),
307            None => self.observed.emit_stdout(s)
308        }
309    }
310
311    #[inline]
312    fn emit_stderr(&self, s: &str) {
313        match self.rule {
314            Some(rule) => self.observed.emit_task_stderr(rule, self.task, s),
315            None => self.observed.emit_stderr(s)
316        }
317    }
318}
319
320impl<E> BndBuilderObserver for RuleTaskEventDispatcher<'_, '_, '_, E>
321where E: BndBuilderObserved
322{
323    fn update(&mut self, event: BndBuilderEvent) {
324        unreachable!()
325    }
326}
327
328#[derive(Default, Debug)]
329pub struct BndBuilderDefaultObserver {}
330
331impl BndBuilderDefaultObserver {
332    pub fn new() -> Rc<RefCell<Box<dyn BndBuilderObserver>>> {
333        Rc::new(RefCell::new(Box::new(BndBuilderDefaultObserver {})))
334    }
335}
336
337impl EventObserver for BndBuilderDefaultObserver {
338    fn emit_stdout(&self, s: &str) {
339        print!("{s}");
340    }
341
342    fn emit_stderr(&self, s: &str) {
343        eprint!("{s}");
344    }
345}
346
347impl BndBuilderObserver for BndBuilderDefaultObserver {
348    fn update(&mut self, event: BndBuilderEvent) {
349        match event {
350            BndBuilderEvent::ChangeState(s) => {
351                match s {
352                    BndBuilderState::ComputeDependencies(p) => {
353                        println!("> Compute dependencies for rule `{p}`")
354                    },
355                    BndBuilderState::RunTasks => println!("> Execute tasks"),
356                    BndBuilderState::Finish => println!("> Done.")
357                }
358            },
359            BndBuilderEvent::StartRule { rule, nb, out_of } => {
360                println!("[{nb}/{out_of}] Handle {rule}")
361            },
362            BndBuilderEvent::StopRule(_) => {},
363            BndBuilderEvent::FailedRule(_) => todo!(),
364            BndBuilderEvent::StartTask(r, t) => {
365                println!("\t$ {t}");
366            },
367            BndBuilderEvent::StopTask(r, t, d) => {
368                println!(
369                    "\tElapsed time: {}",
370                    fancy_duration::FancyDuration(d).truncate(1)
371                )
372            },
373            BndBuilderEvent::TaskStdout(tgt, task, txt) => {
374                for line in txt.lines() {
375                    println!("[{tgt}]\t{line}")
376                }
377            },
378            BndBuilderEvent::TaskStderr(tgt, task, txt) => {
379                for line in txt.lines() {
380                    eprintln!("[{tgt}]\t{line}")
381                }
382            },
383            BndBuilderEvent::Stdout(s) => print!("{s}"),
384            BndBuilderEvent::Stderr(s) => print!("{s}")
385        }
386    }
387}