cxc/unit/
add_external.rs

1use std::{iter::once};
2
3use indexmap::IndexMap;
4
5use crate::{
6    FuncType, Type, TypeEnum,
7    TypeRelation, Unit, XcReflect, parse::{FuncCode, VarDecl, Expr}, VarName, typ::{spec_from_type::type_to_type_spec, ABI},
8};
9
10use super::{backends::IsBackend, ProcessedFuncInfo};
11
12pub struct ExternalFuncAdd {
13    pub ret_type: Type,
14    pub arg_types: Vec<Type>,
15    pub abi: ABI,
16    pub relation: TypeRelation,
17    pub generics: Vec<Type>,
18}
19
20impl ExternalFuncAdd {
21    pub fn empty() -> Self {
22        ExternalFuncAdd {
23            ret_type: Type::void(),
24            arg_types: Vec::new(),
25            relation: TypeRelation::Unrelated,
26            generics: Vec::new(),
27            abi: ABI::Rust,
28        }
29    }
30
31    pub fn method_of(mut self, typ: Type) -> Self {
32        self.relation = TypeRelation::MethodOf(typ.clone());
33        self.arg_types.insert(0, typ);
34        self
35    }
36}
37
38impl Unit {
39    pub fn add_rust_func<A: XcReflect, R: XcReflect>(
40        &mut self, 
41        name: &str, 
42        function: [fn(A) -> R; 1],
43    ) {
44        let func_type = self.comp_data.type_of_val(&function[0]);
45        let TypeEnum::Func(FuncType { args, ret: ret_type, abi }) = 
46            func_type.as_type_enum() else { panic!() };
47
48        let ext_add = ExternalFuncAdd {
49            arg_types: args.clone(),
50            ret_type: ret_type.clone(),
51            abi: *abi,
52            ..ExternalFuncAdd::empty()
53        };
54
55        let function_ptr: *const usize = function[0] as *const usize;
56
57        self.add_rust_func_explicit(name, function_ptr, ext_add)
58    }
59
60    pub fn add_external_default<T: Default + XcReflect>(&mut self) {
61        let typ = self.get_reflect_type::<T>().unwrap();
62        self.add_rust_func_explicit(
63            "default",
64            T::default as *const usize,
65            ExternalFuncAdd {
66                ret_type: typ.clone(),
67                relation: TypeRelation::Static(typ),
68                ..ExternalFuncAdd::empty()
69            },
70        );
71    }
72
73    pub fn add_external_clone<T: Clone + XcReflect>(&mut self) {
74        let typ = self.get_reflect_type::<T>().unwrap();
75        self.add_rust_func_explicit(
76            "clone",
77            T::clone as *const usize,
78            ExternalFuncAdd {
79                arg_types: vec![typ.get_ref()],
80                ret_type: typ.clone(),
81                relation: TypeRelation::MethodOf(typ.get_ref()),
82                ..ExternalFuncAdd::empty()
83            },
84        );
85    }
86
87    pub fn add_external_to_string<T: ToString + XcReflect>(&mut self) {
88        let string_type = self.comp_data.get_by_name(&"String".into()).unwrap();
89        let typ = self.get_reflect_type::<T>().unwrap();
90
91        self.add_rust_func_explicit(
92            "to_string",
93            T::to_string as *const usize,
94            ExternalFuncAdd {
95                ret_type: string_type,
96                ..ExternalFuncAdd::empty()
97            }
98            .method_of(typ.get_ref()),
99        );
100    }
101
102    pub fn add_rust_func_explicit(
103        &mut self,
104        name: &str,
105        function_ptr: *const usize,
106        ext_add: ExternalFuncAdd,
107    ) {
108        let func_type = FuncType {
109            ret: ext_add.ret_type,
110            args: ext_add.arg_types,
111            abi: ext_add.abi,
112        };
113
114        let func_code_id = self.comp_data.func_code.insert(FuncCode {
115            name: name.into(),
116            relation: ext_add.relation.clone().map_inner_type(type_to_type_spec),
117            args: func_type.args.iter().map(|a| VarDecl {
118                name: VarName::None,
119                type_spec: type_to_type_spec(a.clone()),
120            }).collect(),
121            ret_type: type_to_type_spec(func_type.ret.clone()),
122            generic_count: ext_add.generics.len(),
123            is_external: true,
124            abi: ABI::Rust,
125            ..FuncCode::empty()
126        });
127
128        let func_id = self.comp_data.processed.insert(ProcessedFuncInfo {
129            specified_dependencies: IndexMap::new(),
130            name: name.into(),
131            relation: ext_add.relation,
132            generics: ext_add.generics,
133            typ: func_type.clone(),
134        });
135
136        self.comp_data.realizations.insert(func_code_id, once(func_id).collect());
137
138        self.backend.add_external_func(
139            func_id, 
140            func_type,
141            &self.comp_data.processed[func_id],
142            function_ptr, 
143        );
144    }
145}