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}