1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ConstPos {
13 None,
15 West,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum CType {
23 Int8,
25 Int16,
27 Int32,
29 Int64,
31 Uint8,
34 Uint16,
36 Uint32,
38 Uint64,
40 Float,
42 Double,
44 Bool,
46 Size,
48 Char,
50 Void,
52 CancelToken,
54 Error,
56 Enum {
58 module: String,
60 name: String,
62 },
63 StructTag {
65 module: String,
67 name: String,
69 },
70 VtableTag {
72 module: String,
75 name: String,
77 },
78 Named(String),
82 Ptr {
84 konst: ConstPos,
86 pointee: Box<CType>,
88 },
89}
90
91impl CType {
92 pub fn ptr(pointee: CType) -> CType {
94 CType::Ptr {
95 konst: ConstPos::None,
96 pointee: Box::new(pointee),
97 }
98 }
99
100 pub fn const_ptr(pointee: CType) -> CType {
102 CType::Ptr {
103 konst: ConstPos::West,
104 pointee: Box::new(pointee),
105 }
106 }
107
108 pub fn is_pointer(&self) -> bool {
110 matches!(self, CType::Ptr { .. })
111 }
112
113 pub fn render_rust(&self, prefix: &str) -> String {
130 match self {
131 CType::Int8 => "i8".to_string(),
132 CType::Int16 => "i16".to_string(),
133 CType::Int32 => "i32".to_string(),
134 CType::Int64 => "i64".to_string(),
135 CType::Uint8 => "u8".to_string(),
136 CType::Uint16 => "u16".to_string(),
137 CType::Uint32 => "u32".to_string(),
138 CType::Uint64 => "u64".to_string(),
139 CType::Float => "f32".to_string(),
140 CType::Double => "f64".to_string(),
141 CType::Bool => "bool".to_string(),
142 CType::Size => "usize".to_string(),
143 CType::Char => "c_char".to_string(),
144 CType::Void => "std::ffi::c_void".to_string(),
145 CType::CancelToken => "::weaveffi::abi::FfiCancelToken".to_string(),
148 CType::Error => "::weaveffi::abi::FfiError".to_string(),
149 CType::Enum { .. } => "i32".to_string(),
151 CType::StructTag { module, name } => format!("{prefix}_{module}_{name}"),
152 CType::VtableTag { module, name } => format!("{prefix}_{module}_{name}_vtable"),
153 CType::Named(core) => format!("{prefix}_{core}"),
154 CType::Ptr { konst, pointee } => {
155 let inner = pointee.render_rust(prefix);
156 match konst {
157 ConstPos::None => format!("*mut {inner}"),
158 ConstPos::West => format!("*const {inner}"),
159 }
160 }
161 }
162 }
163
164 pub fn render_c(&self, prefix: &str) -> String {
167 match self {
168 CType::Int8 => "int8_t".to_string(),
169 CType::Int16 => "int16_t".to_string(),
170 CType::Int32 => "int32_t".to_string(),
171 CType::Int64 => "int64_t".to_string(),
172 CType::Uint8 => "uint8_t".to_string(),
173 CType::Uint16 => "uint16_t".to_string(),
174 CType::Uint32 => "uint32_t".to_string(),
175 CType::Uint64 => "uint64_t".to_string(),
176 CType::Float => "float".to_string(),
177 CType::Double => "double".to_string(),
178 CType::Bool => "bool".to_string(),
179 CType::Size => "size_t".to_string(),
180 CType::Char => "char".to_string(),
181 CType::Void => "void".to_string(),
182 CType::CancelToken => format!("{prefix}_cancel_token"),
183 CType::Error => format!("{prefix}_error"),
184 CType::Enum { module, name } => format!("{prefix}_{module}_{name}"),
185 CType::StructTag { module, name } => format!("{prefix}_{module}_{name}"),
186 CType::VtableTag { module, name } => format!("{prefix}_{module}_{name}_vtable"),
187 CType::Named(core) => format!("{prefix}_{core}"),
188 CType::Ptr { konst, pointee } => {
189 let inner = pointee.render_c(prefix);
190 match konst {
191 ConstPos::None => format!("{inner}*"),
192 ConstPos::West => format!("const {inner}*"),
193 }
194 }
195 }
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn scalars_render() {
205 assert_eq!(CType::Int32.render_c("weaveffi"), "int32_t");
206 assert_eq!(CType::Size.render_c("weaveffi"), "size_t");
207 assert_eq!(CType::Error.render_c("myffi"), "myffi_error");
208 }
209
210 #[test]
211 fn string_pointer_renders_with_west_const() {
212 let s = CType::const_ptr(CType::Char);
213 assert_eq!(s.render_c("weaveffi"), "const char*");
214 assert_eq!(CType::ptr(CType::Char).render_c("weaveffi"), "char*");
215 }
216
217 #[test]
218 fn struct_and_vtable_tags_use_prefix_and_module() {
219 let t = CType::StructTag {
220 module: "contacts".into(),
221 name: "Book".into(),
222 };
223 assert_eq!(t.render_c("weaveffi"), "weaveffi_contacts_Book");
224 assert_eq!(
225 CType::ptr(t).render_c("weaveffi"),
226 "weaveffi_contacts_Book*"
227 );
228 let v = CType::VtableTag {
229 module: "events".into(),
230 name: "Listener".into(),
231 };
232 assert_eq!(
233 CType::const_ptr(v.clone()).render_c("weaveffi"),
234 "const weaveffi_events_Listener_vtable*"
235 );
236 assert_eq!(
237 CType::const_ptr(v).render_rust("weaveffi"),
238 "*const weaveffi_events_Listener_vtable"
239 );
240 }
241
242 #[test]
243 fn named_type_is_prefixed() {
244 assert_eq!(
245 CType::Named("events_fetch_callback".into()).render_c("weaveffi"),
246 "weaveffi_events_fetch_callback"
247 );
248 }
249
250 #[test]
251 fn rust_scalars_render() {
252 assert_eq!(CType::Int32.render_rust("weaveffi"), "i32");
253 assert_eq!(CType::Uint8.render_rust("weaveffi"), "u8");
254 assert_eq!(CType::Float.render_rust("weaveffi"), "f32");
255 assert_eq!(CType::Double.render_rust("weaveffi"), "f64");
256 assert_eq!(CType::Bool.render_rust("weaveffi"), "bool");
257 assert_eq!(CType::Size.render_rust("weaveffi"), "usize");
258 }
259
260 #[test]
261 fn rust_runtime_types_name_the_runtime_structs() {
262 assert_eq!(
263 CType::Error.render_rust("acme"),
264 "::weaveffi::abi::FfiError"
265 );
266 assert_eq!(
267 CType::CancelToken.render_rust("acme"),
268 "::weaveffi::abi::FfiCancelToken"
269 );
270 }
271
272 #[test]
273 fn rust_string_param_is_const_char_pointer() {
274 assert_eq!(
275 CType::const_ptr(CType::Char).render_rust("weaveffi"),
276 "*const c_char"
277 );
278 assert_eq!(
279 CType::ptr(CType::Char).render_rust("weaveffi"),
280 "*mut c_char"
281 );
282 }
283
284 #[test]
285 fn rust_c_style_enum_lowers_to_i32() {
286 let e = CType::Enum {
287 module: "gfx".into(),
288 name: "Color".into(),
289 };
290 assert_eq!(e.render_rust("weaveffi"), "i32");
291 }
292
293 #[test]
294 fn rust_void_is_only_a_pointee() {
295 assert_eq!(
296 CType::ptr(CType::Void).render_rust("weaveffi"),
297 "*mut std::ffi::c_void"
298 );
299 }
300}