faux/mock/
store.rs

1use std::collections::HashMap;
2
3use crate::InvocationError;
4
5use super::{unchecked::Unchecked, Mock};
6
7#[derive(Debug)]
8pub struct Store<'stub> {
9    pub struct_name: &'static str,
10    stubs: HashMap<usize, Unchecked<'stub>>,
11}
12
13impl<'stub> Store<'stub> {
14    pub fn new(struct_name: &'static str) -> Self {
15        Store {
16            struct_name,
17            stubs: HashMap::new(),
18        }
19    }
20
21    /// Returns a mutable reference to a [`Mock`] for a given function
22    ///
23    /// If the given function has not yet been mocked, an empty mock
24    /// is created for the function.
25    pub fn get_mut<R, I, O>(
26        &mut self,
27        id: fn(R, I) -> O,
28        fn_name: &'static str,
29    ) -> &mut Mock<'stub, I, O> {
30        let mock = self.stubs.entry(id as usize).or_insert_with(|| {
31            let mock: Mock<I, O> = Mock::new(fn_name);
32            mock.into()
33        });
34
35        let mock = unsafe { mock.as_typed_mut() };
36        assert_name(mock, fn_name);
37        mock
38    }
39
40    /// Returns a reference to a [`Mock`] for a given function
41    ///
42    /// `None` is returned if the function was never mocked
43    pub unsafe fn get<R, I, O>(
44        &self,
45        id: fn(R, I) -> O,
46        fn_name: &'static str,
47        generics: &'static str,
48    ) -> Result<&Mock<'stub, I, O>, InvocationError> {
49        match self.stubs.get(&(id as usize)).map(|m| m.as_typed()) {
50            Some(mock) => {
51                assert_name(mock, fn_name);
52                Ok(mock)
53            }
54            None => Err(InvocationError {
55                fn_name,
56                struct_name: self.struct_name,
57                generics,
58                stub_error: super::InvocationError::NeverStubbed,
59            }),
60        }
61    }
62}
63
64fn assert_name<I, O>(mock: &Mock<I, O>, fn_name: &'static str) {
65    assert_eq!(
66        mock.name(),
67        fn_name,
68        "faux bug: conflicting mock names: '{}' vs '{}'",
69        mock.name(),
70        fn_name
71    );
72}