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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Trait and implementation for [`WorldInteractor`]

use crate::prelude::*;
use std::fmt::Debug;
use std::time::Duration;

mod world_interactor_impl;
pub use self::world_interactor_impl::*;

mod interactable;
pub use self::interactable::*;

#[cfg(any(test, feature = "use-mocks"))]
pub use self::mocks::*;

/// Provides information to an [`ObjectBehavior`] about
/// the world it is placed in.
///
/// [`ObjectBehavior`]: ./trait.ObjectBehavior.html
pub trait WorldInteractor: Debug {
    /// Scans for objects in the area defined by an [`Aabb`].
    ///
    /// Returns all objects either completely contained or intersecting
    /// with the area.
    ///
    /// [`Aabb`]: ./struct.Aabb.html
    fn find_objects_in_area(&self, area: Aabb) -> Snapshot<'_>;

    /// Returns the amount of time that passed since the last call
    /// to the `step` function of [`Simulation`]
    fn elapsed_time_in_update(&self) -> Duration;
}

#[cfg(any(test, feature = "use-mocks"))]
mod mocks {
    use super::*;
    use std::cell::RefCell;
    use std::thread::panicking;

    /// Mock for [`WorldInteractor`]
    ///
    /// [`WorldInteractor`]: ../trait.WorldInteractor.html
    #[derive(Debug, Default)]
    pub struct WorldInteractorMock<'a> {
        expect_find_objects_in_area_and_return: Option<(Aabb, Snapshot<'a>)>,
        expect_elapsed_time_in_update_and_return: Option<(Duration,)>,

        find_objects_in_area_was_called: RefCell<bool>,
        elapsed_time_in_update_was_called: RefCell<bool>,
    }

    impl<'a> WorldInteractorMock<'a> {
        /// Constructs a new `WorldInteractorMock`
        pub fn new() -> Self {
            Default::default()
        }

        /// Expect a call to `find_objects_in_area`
        pub fn expect_find_objects_in_area_and_return(
            &mut self,
            area: Aabb,
            return_value: Snapshot<'a>,
        ) {
            self.expect_find_objects_in_area_and_return = Some((area, return_value));
        }

        /// Expect a call to `elapsed_time_in_update`
        pub fn expect_elapsed_time_in_update_and_return(&mut self, return_value: Duration) {
            self.expect_elapsed_time_in_update_and_return = Some((return_value,));
        }
    }

    impl<'a> WorldInteractor for WorldInteractorMock<'a> {
        fn find_objects_in_area(&self, area: Aabb) -> Snapshot<'_> {
            *self.find_objects_in_area_was_called.borrow_mut() = true;

            let (expected_area, return_value) = self
                .expect_find_objects_in_area_and_return
                .clone()
                .expect("find_objects_in_area() was called unexpectedly");

            assert_eq!(
                expected_area, area,
                "find_objects_in_area() was called with {:?}, expected {:?}",
                area, expected_area
            );

            return_value.clone()
        }

        fn elapsed_time_in_update(&self) -> Duration {
            *self.elapsed_time_in_update_was_called.borrow_mut() = true;

            let (return_value,) = self
                .expect_elapsed_time_in_update_and_return
                .expect("elapsed_time_in_update() was called unexpectedly");

            return_value
        }
    }

    impl<'a> Drop for WorldInteractorMock<'a> {
        fn drop(&mut self) {
            if panicking() {
                return;
            }

            assert!(
                self.expect_find_objects_in_area_and_return.is_some()
                    == *self.find_objects_in_area_was_called.borrow(),
                "find_objects_in_area() was not called, but expected"
            );

            assert!(
                self.expect_elapsed_time_in_update_and_return.is_some()
                    == *self.elapsed_time_in_update_was_called.borrow(),
                "elapsed_time_in_update() was not called, but expected"
            );
        }
    }
}