Skip to main content

annotate/
function.rs

1use alloc::vec::Vec;
2use core::any::{TypeId, type_name};
3use core::fmt;
4use core::fmt::{Debug, Formatter};
5
6use crate::internal::environment::ProtoEnvironment;
7use crate::internal::function::ProtoFunction;
8use crate::{Attribute, Environment, Module, Path};
9
10#[derive(Clone)]
11pub struct Function {
12    pub(crate) environment: &'static ProtoEnvironment,
13    pub(crate) proto_function: &'static ProtoFunction,
14}
15
16impl Function {
17    pub const fn name(&self) -> &'static str {
18        self.proto_function.name
19    }
20
21    pub const fn module(&self) -> Option<Module> {
22        if let Some(id) = self.proto_function.module {
23            return Some(self.environment.get_module(id));
24        }
25        None
26    }
27
28    pub const fn path(&self) -> &'static Path {
29        &self.proto_function.path
30    }
31
32    pub fn find_attributes_such_that(
33        &self,
34        f: impl Fn(&Attribute) -> bool,
35    ) -> Vec<&'static Attribute> {
36        self.attributes()
37            .into_iter()
38            .filter(|attribute| f(attribute))
39            .collect()
40    }
41
42    pub fn has_attribute_such_that(&self, f: impl Fn(&Attribute) -> bool) -> bool {
43        self.attributes().into_iter().any(f)
44    }
45
46    pub fn same_as<F: 'static>(&self) -> bool {
47        unsafe { (self.proto_function.function)() }.raw.is::<F>()
48    }
49
50    pub fn cast<F: 'static>(&self) -> Result<&'static F, TypeMismatch> {
51        unsafe { (self.proto_function.function)() }
52            .raw
53            .downcast_ref::<F>()
54            .ok_or_else(|| TypeMismatch {
55                type_name: type_name::<F>(),
56                type_id: TypeId::of::<F>(),
57                expected_type_id: (unsafe { (self.proto_function.function)() }).raw.type_id(),
58            })
59    }
60
61    pub fn try_call<F: 'static, R>(&self, invoke: impl FnOnce(&F) -> R) -> Result<R, TypeMismatch> {
62        self.cast::<F>().map(invoke)
63    }
64
65    pub fn call<F: 'static, R>(&self, invoke: impl FnOnce(&F) -> R) -> R {
66        self.try_call::<F, R>(invoke).unwrap()
67    }
68}
69
70impl Debug for Function {
71    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
72        f.debug_struct(type_name::<Self>())
73            .field("proto_function", &self.proto_function)
74            .field("environment", &type_name::<Environment>())
75            .finish()
76    }
77}
78
79impl PartialEq for Function {
80    fn eq(&self, other: &Self) -> bool {
81        core::ptr::eq(self.environment, other.environment)
82            && core::ptr::eq(self.proto_function, other.proto_function)
83    }
84}
85
86impl Eq for Function {}
87
88#[derive(Debug, Eq, PartialEq, Clone)]
89pub struct TypeMismatch {
90    type_name: &'static str,
91    type_id: TypeId,
92    expected_type_id: TypeId,
93}