pit_c/
lib.rs

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}