xmachine/
function.rs

1use crate::Ref;
2use core::fmt::{Display, Error, Formatter};
3
4use alloc::string::ToString;
5
6/// Represents a function that takes a &mut I, returns O,
7/// and contains a captured context C.
8#[derive(Clone)]
9pub struct Function<I, O, C> {
10    /// Function pointer to call
11    function_ptr: Ref<dyn Fn(&mut I) -> O>,
12    /// The captured context of the function
13    context: C,
14}
15
16/// Represents a function that takes a &mut I, returns O,
17/// and contains a captured context C.
18impl<I, O, C> Function<I, O, C> {
19    /// Create a function from a function pointer and captured context
20    /// We use a function pointer because a non-capturing lambda can
21    /// decay into a function pointer, and because it's sized!
22    pub fn new(function_ptr: impl 'static + Fn(&mut I) -> O, context: C) -> Self {
23        Self {
24            function_ptr: Ref::new(function_ptr),
25            context,
26        }
27    }
28
29    /// Return the captured context of the Function
30    pub fn get_context(&self) -> &C {
31        &self.context
32    }
33
34    /// Call this function with an input and return the output
35    pub fn call(&self, input: &mut I) -> O {
36        (self.function_ptr)(input)
37    }
38}
39
40impl<I, O, C> Display for Function<I, O, C> {
41    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
42        let ptr = Ref::into_raw(self.function_ptr.clone()) as *const u8;
43        write!(f, "<fn at {}>", format!("{:?}", ptr)[..8].to_string())?;
44        unsafe {
45            Ref::from_raw(ptr);
46        }
47        Ok(())
48    }
49}
50
51/// == operator for Function
52/// This doesn't compare the function pointer,
53/// but instead compares the contexts. If the contexts are the same,
54/// it's almost guaranteed that these two functions are the same.
55impl<I, O, C> PartialEq for Function<I, O, C> {
56    fn eq(&self, rhs: &Self) -> bool {
57        format!("{}", self) == format!("{}", rhs)
58    }
59}
60
61/// Ord operators for Function
62/// This doesn't compare the function pointer,
63/// but instead compares the contexts.
64impl<I, O, C: PartialOrd> PartialOrd for Function<I, O, C> {
65    fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
66        self.context.partial_cmp(&rhs.context)
67    }
68}
69
70impl<I, O, C> Default for Function<I, O, C>
71where
72    I: Default,
73    O: Default,
74    C: Default,
75{
76    fn default() -> Self {
77        Self::new(|_: &mut I| Default::default(), Default::default())
78    }
79}