1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! This executable spins up the dummy hardware data manager and tries to localize
//! the updates it receives. It then displays the calculated locations on top of the
//! original locations that were used to generate the updates so that we can assess
//! the performance of the localization algorithm.

mod gui;

use std::sync::{Arc, Mutex};

use cybergrape::dummy_hdm::DummyHdm;
use cybergrape::localizer::localize_points;
use cybergrape::update_accumulator::UpdateAccumulator;
use gui::engage_gui;

fn main() {
    // Configure, instantiate, and start the dummy HDM.
    let hdm = DummyHdm::builder()
        .num_points(10)
        .range(5.0)
        .noise(0.25)
        .build();

    // We're going to need a few references active to this HDM at once, so we
    // wrap it in a RefCell to indicate that we want to enforce the borrow checking
    // rules at _runtime_ rather than compile-time. The Rc allows us to keep
    // references to the data in several different scopes.
    //
    // This is called the **interior mutability pattern**.
    let hdm_rf = Arc::new(Mutex::new(hdm));

    // Now we're going to shadow over the hdm variable with a reference so that
    // we don't accidentially do something funky with the original thing.
    let hdm = hdm_rf.clone();

    // Instantiate an UpdateAccumulator with a pointer to the HDM.
    let update_acc_hdm_handle = hdm_rf.clone();
    let mut update_acc = UpdateAccumulator::new(update_acc_hdm_handle);

    let debug_hdm_handle = hdm_rf.clone();

    // Ok now this is the wonky bit. We're going to define closures to pass into
    // this function. The || indicates that this is a closure that takes no arguments
    // and move indicates that captured variables will be _moved_ into the scope
    // of the function, rather than being borrowed.
    //
    // So, we move the debug_hdm_handle into the first closure, then .borrow()
    // to turn the Rc<RefCell<T>> into an &T, which we can then call the
    // .get_debug_locations() on.
    //
    // Remember that those closures are **not** being run immediately, they are
    // instead run roughly every quarter second by the GUI.
    let _ = engage_gui(
        Box::new(move || debug_hdm_handle.lock().unwrap().get_debug_locations()),
        Box::new(move || localize_points(&update_acc.get_status())),
    );

    // Once the gui terminates, we take a mutable referene to the hdm and stop it.
    // .borrow_mut() takes the Rc<RefCell<T>> and turns it into an &mut T.
    hdm.lock().unwrap().stop();
}