1use std::iter::once;
2
3use itertools::Itertools;
4use pit_core::{Arg, Interface, ResTy};
5
6pub fn cify(i: &Interface) -> String {
7 let rid = i.rid_str();
8 let iface = i
9 .methods
10 .iter()
11 .map(|(a, b)| {
12 format!(
13 "vfunc(R{rid}_{a}_res,R{rid}_{a},VSelf,{})",
14 b.params.iter().map(|a| cty(i, a, &FFIKind::C {})).join(",")
15 )
16 })
17 .join(" ");
18 let types = i
19 .methods
20 .iter()
21 .map(|(a, b)| {
22 format!(
23 r#"
24 typedef struct R{rid}_{a}_res{{
25 {}
26 }} R{rid}_{a}_res;
27 typedef struct R{rid}_{a}_fres{{
28 {}
29 }} R{rid}_{a}_fres;
30 "#,
31 b.rets
32 .iter()
33 .enumerate()
34 .map(|(idx, a)| {
35 let a = cty(i, a, &FFIKind::C {});
36 format!("{a} v{idx}")
37 })
38 .join(";"),
39 b.rets
40 .iter()
41 .enumerate()
42 .map(|(idx, a)| {
43 let a = cty(i, a, &FFIKind::FFI);
44 format!("{a} v{idx}")
45 })
46 .join(";")
47 )
48 })
49 .join(";");
50 let impls = i
51 .methods
52 .iter()
53 .map(|(a, b)| {
54 format!(
55 r#"
56 static __attribute__((import_module("pit/{rid}"), import_name("{a}"))) R{rid}_{a}_fres R{rid}_{a}_impl({});
57 R{rid}_{a}_res handle_t_R{rid}_{a}({}){{
58 VSELF(handle_t);
59 R{rid}_{a}_fres fres = R{rid}_{a}_impl(handle_borrow(self),{});
60 return R{rid}_{a}_res{{
61 {}
62 }};
63 }};
64 __attribute__((export_name("pit/{rid}/~c_impl/{a}"))) static R{rid}_{a}_fres R{rid}_{a}_export({}){{
65 R{rid}_{a}_res res = VCALL(me,R{rid}_{a},{});
66 return R{rid}_{a}_fres{{
67 {}
68 }};
69 }};
70 "#,
71 b.rets
72 .iter()
73 .enumerate()
74 .map(|(idx, a)| {
75 let a = cty(i, a, &FFIKind::FFI);
76 format!("{a} v{idx}")
77 })
78 .join(","),
79 once(format!("__externref_t self")).chain(b.params
80 .iter()
81 .enumerate()
82 .map(|(idx, a)| {
83 let a = cty(i, a, &FFIKind::C {});
84 format!("{a} v{idx}")
85 }))
86 .join(","),
87 b.params.iter().enumerate().map(|(idx,a)|{
88 let mut s = format!("v{idx}");
89 if let Arg::Resource { ty, nullable, take, ann } = a{
90 s = format!("handle_new({s})");
91 if !matches!(ty,ResTy::None){
92 let c = cty(i, a, &FFIKind::C { });
93 s = format!("DYN(handle_t,{c},({{
94 handle_t handle = {s};
95 handle_t* h = malloc(sizeof(handle_t));
96 *h = handle;
97 h
98 }}))")
99 }
100 }
101 return s;
102 }).join(","),
103 b.rets.iter().enumerate().map(|(idx,a)|{
104 let mut s = format!("fres.v{idx}");
105 if let Arg::Resource { ty, nullable, take, ann } = a{
106 if !matches!(ty,ResTy::None){
107 let c = cty(i, a, &FFIKind::C { });
108 s = format!("{c}_ref({s})")
109 }
110 s = format!("handle_pop({s})")
111 }
112 return s;
113 }).join(","),
114 once(format!("R{rid} me")).chain(b.params
115 .iter()
116 .enumerate()
117 .map(|(idx, a)| {
118 let a = cty(i, a, &FFIKind::FFI);
119 format!("{a} v{idx}")
120 }))
121 .join(","),
122 b.params.iter().enumerate().map(|(idx,a)|{
123 let mut s = format!("v{idx}");
124 if let Arg::Resource { ty, nullable, take, ann } = a{
125 if !matches!(ty,ResTy::None){
126 let c = cty(i, a, &FFIKind::C { });
127 s = format!("{c}_ref({s})")
128 }
129 s = format!("handle_{}({s})",if *take{
130 "pop"
131 }else{
132 "borrow"
133 })
134 }
135 return s;
136 }).join(","),
137 b.rets.iter().enumerate().map(|(idx,a)|{
138 let mut s = format!("res.v{idx}");
139 if let Arg::Resource { ty, nullable, take, ann } = a{
140 s = format!("handle_new({s})");
141 if !matches!(ty,ResTy::None){
142 let c = cty(i, a, &FFIKind::C { });
143 s = format!("DYN(handle_t,{c},({{
144 handle_t handle = {s};
145 handle_t* h = malloc(sizeof(handle_t));
146 *h = handle;
147 h
148 }}))")
149 }
150 }
151 return s;
152 }).join(","),
153 )
154 })
155 .join(";\n");
156 format!(
157 r#"
158 #ifndef R{rid}
159 #define R{rid}
160 #include <interface99.h>
161 #include <handle.h>
162 #include <stdint.h>
163 #define R{rid}_IFACE {iface}
164 #define R{rid}_EXTENDS (Droppable)
165 {types}
166 interface(R{rid});
167 declImplExtern(R{rid},handle_t);
168 extern __externref_t R{rid}_ref(R{rid} rid);
169 #define R{rid}_of(a) handle_new(R{rid}_ref(a))
170 #endif
171 #ifdef R{rid}_IMPL
172 __attribute__((import_module("pit/{rid}"), import_name("~c_impl"))) extern __externref_t $$of_${rid}({rid} rid);
173 __externref_t R{rid}_ref({rid} rid){{
174 return $$of_${rid}(rid);
175 }};
176 __attribute__((export_name("pit/{rid}/~c_impl.drop"))) static void drop({rid} rid){{
177 VCALL_SUPER(rid,Droppable,drop);
178 free(rid.self);
179 }};
180 {impls}
181 implExtern(R{rid},handle_t);
182 #endif
183 "#
184 )
185}
186pub enum FFIKind {
187 FFI,
188 C {},
189}
190pub fn cty(i: &Interface, t: &Arg, ffi_kind: &FFIKind) -> String {
191 match t {
192 Arg::I32 => format!("uint32_t"),
193 Arg::I64 => format!("uint64_t"),
194 Arg::F32 => format!("float"),
195 Arg::F64 => format!("double"),
196 Arg::Resource {
197 ty,
198 nullable,
199 take,
200 ann,
201 } => match ffi_kind {
202 FFIKind::FFI => format!("__externref_t"),
203 FFIKind::C {} => match ty {
204 pit_core::ResTy::None => format!("handle_t"),
205 pit_core::ResTy::Of(a) => format!("R{}", hex::encode(a)),
206 pit_core::ResTy::This => format!("R{}", i.rid_str()),
207 _ => todo!()
208 },
209 },
210 _ => todo!()
211 }
212}