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
use std::{hash::Hash, rc::Rc};

use crate::utils::debug;

/// Callback is a wrapper around a function that is used to send messages to the [Component](../trait.Component.html).
/// 
/// `IN` is the type of the input of the wrapped function.
/// Meaning if we would like to send a message to the [component](../trait.Component.html) we need to provide input of type `IN`.
/// Callback should be used for defining child to parent [component](../trait.Component.html) communication and subscribing
/// to HTML [events](../../events/index.html).
pub struct Callback<IN> {
    wrapper: Rc<dyn Fn(IN)>,
}

impl<IN> Callback<IN> {
    /// Function that creates a new instance of the Callback.
    /// Using a Callback defined by this function will not send [messages](../trait.Component.html#associatedtype.Message) to the [component](../trait.Component.html).
    /// It should be used only if the Callback is to send [messages](../trait.Component.html#associatedtype.Message)
    /// to the father [component](../trait.Component.html) and this logic should be contained in `wrapper` argument function.
    /// If sending the [message](../trait.Component.html#associatedtype.Message) to the current [component](../trait.Component.html)
    /// is the goal [create_callback](../behavior/trait.Behavior.html#tymethod.create_callback) function should be used.
    pub fn new<F>(wrapper: F) -> Self
    where
        F: Fn(IN) + 'static,
    {
        Callback {
            wrapper: Rc::new(wrapper),
        }
    }

    /// Function that calls the [Callback] using the provided `input`.
    pub fn emit(&self, input: IN) {
        debug::log("Emitting callback");
        (self.wrapper)(input);
    }
}

impl<IN> Hash for Callback<IN> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        let ptr = self.wrapper.as_ref() as *const dyn Fn(IN);
        ptr.hash(state);
    }
}

impl<IN> Clone for Callback<IN> {
    fn clone(&self) -> Self {
        Self {
            wrapper: self.wrapper.clone(),
        }
    }
}