1use std::env;
2use std::path::{Path, PathBuf};
3use std::rc::Rc;
4
5use heck::ToUpperCamelCase;
6
7use crate::backend::*;
8use crate::model::*;
9
10use crate::backend::rust::rust_struct::RustStruct;
11use crate::backend::rust::rust_type::RustType;
12
13use crate::backend::rust::rust_type::LifetimeInfo;
14use crate::backend::rust::type_converter::TypeConverter;
15
16mod rust_struct;
17mod rust_type;
18mod type_converter;
19
20pub fn generate_ffi(library: &Library) -> FormattingResult<()> {
28 RustCodegen::new(library).generate()
29}
30
31struct RustCodegen<'a> {
32 library: &'a Library,
33 dest_path: PathBuf,
34}
35
36impl<'a> RustCodegen<'a> {
37 fn new(lib: &'a Library) -> Self {
38 RustCodegen {
39 library: lib,
40 dest_path: Path::new(&env::var_os("OUT_DIR").unwrap()).join("ffi.rs"),
41 }
42 }
43
44 fn generate(self) -> FormattingResult<()> {
45 let mut f = FilePrinter::new(&self.dest_path)?;
46
47 for statement in self.library.statements() {
48 match statement {
49 Statement::StructDefinition(s) => match s {
50 StructType::FunctionArg(s) => self.write_struct_definition(&mut f, s)?,
51 StructType::FunctionReturn(s) => self.write_struct_definition(&mut f, s)?,
52 StructType::CallbackArg(s) => self.write_struct_definition(&mut f, s)?,
53 StructType::Universal(s) => self.write_struct_definition(&mut f, s)?,
54 },
55 Statement::EnumDefinition(handle) => self.write_enum_definition(&mut f, handle)?,
56 Statement::FunctionDefinition(handle) => {
57 Self::write_function(&mut f, handle, &self.library.settings.c_ffi_prefix)?
58 }
59 Statement::InterfaceDefinition(t) => {
60 self.write_interface(&mut f, t.untyped(), t.mode())?;
61 }
62 _ => (),
63 }
64 f.newline()?;
65 }
66
67 Ok(())
68 }
69
70 fn write_struct_definition<T>(
71 &self,
72 f: &mut dyn Printer,
73 handle: &Handle<Struct<T, Validated>>,
74 ) -> FormattingResult<()>
75 where
76 T: StructFieldType + RustType,
77 {
78 let struct_name = handle.name().to_upper_camel_case();
79 let c_lifetime = if handle.annotate_c_with_lifetime() {
80 "<'a>"
81 } else {
82 ""
83 };
84 let rust_lifetime = if handle.annotate_rust_with_lifetime() {
85 "<'a>"
86 } else {
87 ""
88 };
89 let public = "pub "; f.writeln("#[repr(C)]")?;
93 f.writeln("#[derive(Clone)]")?;
94 f.writeln(&format!("pub struct {struct_name}{c_lifetime}"))?;
95
96 blocked(f, |f| {
97 for element in &handle.fields {
98 f.writeln(&format!(
99 "{}{}: {},",
100 public,
101 element.name,
102 element.field_type.as_c_type()
103 ))?;
104 }
105 Ok(())
106 })?;
107
108 f.newline()?;
109
110 f.writeln(&format!("impl{c_lifetime} {struct_name}{c_lifetime}"))?;
112 blocked(f, |f| {
113 for field in &handle.fields {
114 let field_lifetime = if field.field_type.rust_requires_lifetime() {
115 "'a "
116 } else {
117 ""
118 };
119 let fn_lifetime =
120 if field.field_type.rust_requires_lifetime() && !handle.c_requires_lifetime() {
121 "<'a>"
122 } else {
123 ""
124 };
125 let ampersand = if field.field_type.is_copyable() {
126 ""
127 } else {
128 "&"
129 };
130
131 f.writeln("#[allow(clippy::needless_lifetimes)]")?;
133 f.writeln(&format!(
134 "pub fn {name}{fn_lifetime}(&{lifetime}self) -> {ampersand}{return_type}",
135 name = field.name,
136 return_type = field.field_type.as_rust_type(),
137 fn_lifetime = fn_lifetime,
138 lifetime = field_lifetime,
139 ampersand = ampersand
140 ))?;
141 blocked(f, |f| {
142 if let Some(conversion) = field.field_type.conversion() {
143 if conversion.is_unsafe() {
144 f.writeln("unsafe {")?;
145 }
146 conversion.convert_from_c(
147 f,
148 &format!(
149 "{ampersand}self.{name}",
150 name = field.name,
151 ampersand = ampersand
152 ),
153 "",
154 )?;
155 if conversion.is_unsafe() {
156 f.writeln("}")?;
157 }
158 Ok(())
159 } else {
160 f.writeln(&format!(
161 "{ampersand}self.{name}",
162 name = field.name,
163 ampersand = ampersand
164 ))
165 }
166 })?;
167
168 f.newline()?;
169
170 f.writeln("#[allow(clippy::needless_lifetimes)]")?;
172 f.writeln(&format!(
173 "pub fn set_{name}{fn_lifetime}(&{lifetime}mut self, value: {element_type})",
174 name = field.name,
175 element_type = field.field_type.as_rust_type(),
176 fn_lifetime = fn_lifetime,
177 lifetime = field_lifetime
178 ))?;
179 blocked(f, |f| {
180 if let Some(conversion) = field.field_type.conversion() {
181 conversion.convert_to_c(f, "value", &format!("self.{} = ", field.name))?;
182 f.write(";")
183 } else {
184 f.writeln(&format!("self.{} = value;", field.name))
185 }
186 })?;
187
188 f.newline()?;
189 }
190 Ok(())
191 })?;
192
193 let rust_struct_name = format!("{struct_name}Fields");
195 if handle.has_conversion() {
196 f.writeln(&format!("pub struct {rust_struct_name}{rust_lifetime}"))?;
197 blocked(f, |f| {
198 for element in &handle.fields {
199 f.writeln(&format!(
200 "pub {}: {},",
201 element.name,
202 element.field_type.as_rust_type()
203 ))?;
204 }
205 Ok(())
206 })?;
207
208 f.writeln(&format!(
210 "impl{rust_lifetime} From<{rust_struct_name}{rust_lifetime}> for {struct_name}{c_lifetime}",
211 ))?;
212 blocked(f, |f| {
213 f.writeln(&format!("fn from(from: {rust_struct_name}) -> Self"))?;
214 blocked(f, |f| {
215 f.writeln("Self")?;
216 blocked(f, |f| {
217 for element in &handle.fields {
218 if let Some(conversion) = element.field_type.conversion() {
219 conversion.convert_to_c(
220 f,
221 &format!("from.{}", element.name),
222 &format!("{}: ", element.name),
223 )?;
224 f.write(",")?;
225 } else {
226 f.writeln(&format!("{name}: from.{name},", name = element.name))?;
227 }
228 }
229 Ok(())
230 })
231 })
232 })
233 } else {
234 f.writeln(&format!(
235 "pub type {rust_struct_name}{c_lifetime} = {struct_name}{c_lifetime};"
236 ))
237 }
238 }
239
240 fn write_enum_definition(
241 &self,
242 f: &mut dyn Printer,
243 handle: &Handle<Enum<Validated>>,
244 ) -> FormattingResult<()> {
245 let enum_name = handle.name.to_upper_camel_case();
246 f.writeln("#[repr(C)]")?;
247 f.writeln("#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd)]")?;
248 f.writeln(&format!("pub enum {enum_name}"))?;
249 blocked(f, |f| {
250 for variant in &handle.variants {
251 f.writeln(&format!(
252 "{} = {},",
253 variant.name.to_upper_camel_case(),
254 variant.value
255 ))?;
256 }
257 Ok(())
258 })?;
259
260 f.writeln(&format!("impl From<{enum_name}> for std::os::raw::c_int"))?;
262 blocked(f, |f| {
263 f.writeln(&format!("fn from(value: {enum_name}) -> Self"))?;
264 blocked(f, |f| {
265 f.writeln("match value")?;
266 blocked(f, |f| {
267 for variant in &handle.variants {
268 f.writeln(&format!(
269 "{}::{} => {},",
270 enum_name,
271 variant.name.to_upper_camel_case(),
272 variant.value
273 ))?;
274 }
275 Ok(())
276 })
277 })
278 })?;
279
280 f.writeln(&format!("impl From<std::os::raw::c_int> for {enum_name}"))?;
281 blocked(f, |f| {
282 f.writeln("fn from(value: std::os::raw::c_int) -> Self")?;
283 blocked(f, |f| {
284 f.writeln("match value")?;
285 blocked(f, |f| {
286 for variant in &handle.variants {
287 f.writeln(&format!(
288 "{} => {}::{},",
289 variant.value,
290 enum_name,
291 variant.name.to_upper_camel_case(),
292 ))?;
293 }
294 f.writeln(&format!(
295 "_ => panic!(\"{{value}} is not a variant of {enum_name}\"),"
296 ))
297 })
298 })
299 })
300 }
301
302 fn write_function(
303 f: &mut dyn Printer,
304 handle: &Handle<Function<Validated>>,
305 prefix: &str,
306 ) -> FormattingResult<()> {
307 f.writeln("#[allow(clippy::missing_safety_doc)]")?;
308 f.writeln("#[no_mangle]")?;
309 f.writeln(&format!(
310 "pub unsafe extern \"C\" fn {}_{}(",
311 prefix, handle.name
312 ))?;
313
314 f.write(
315 &handle
316 .arguments
317 .iter()
318 .map(|param| format!("{}: {}", param.name, param.arg_type.as_c_type()))
319 .collect::<Vec<String>>()
320 .join(", "),
321 )?;
322
323 fn write_error_return(
324 f: &mut dyn Printer,
325 _error: &ErrorType<Validated>,
326 ) -> FormattingResult<()> {
327 f.write(") -> std::os::raw::c_int")
328 }
329
330 match handle.get_signature_type() {
332 SignatureType::NoErrorNoReturn => {
333 f.write(")")?;
334 }
335 SignatureType::NoErrorWithReturn(t, _) => {
336 f.write(&format!(") -> {}", t.as_c_type()))?;
337 }
338 SignatureType::ErrorNoReturn(err) => {
339 write_error_return(f, &err)?;
340 }
341 SignatureType::ErrorWithReturn(err, ret, _) => {
342 if !handle.arguments.is_empty() {
343 f.write(", ")?;
344 }
345 f.write(&format!("out: *mut {}", ret.as_c_type()))?;
346 write_error_return(f, &err)?;
347 }
348 }
349
350 blocked(f, |f| {
351 for param in &handle.arguments {
352 if let Some(converter) = param.arg_type.conversion() {
353 converter.convert_from_c(f, ¶m.name, &format!("let {} = ", param.name))?;
354 f.write(";")?;
355 }
356 }
357
358 fn basic_invocation(f: &mut dyn Printer, name: &str) -> FormattingResult<()> {
359 f.writeln(&format!("crate::{name}("))
360 }
361
362 match handle.get_signature_type() {
364 SignatureType::NoErrorNoReturn => {
365 basic_invocation(f, &handle.name)?;
366 }
367 SignatureType::NoErrorWithReturn(ret, _) => {
368 if ret.has_conversion() {
369 f.writeln(&format!("let _result = crate::{}(", handle.name))?;
370 } else {
371 basic_invocation(f, &handle.name)?;
372 }
373 }
374 SignatureType::ErrorWithReturn(_, _, _) | SignatureType::ErrorNoReturn(_) => {
375 f.writeln(&format!("match crate::{}(", &handle.name))?;
376 }
377 }
378
379 f.write(
380 &handle
381 .arguments
382 .iter()
383 .map(|param| param.name.to_string())
384 .collect::<Vec<String>>()
385 .join(", "),
386 )?;
387 f.write(")")?;
388
389 match handle.get_signature_type() {
390 SignatureType::NoErrorNoReturn => {}
391 SignatureType::NoErrorWithReturn(ret, _) => {
392 if let Some(conversion) = ret.conversion() {
393 f.write(";")?;
394 conversion.convert_to_c(f, "_result", "")?;
395 }
396 }
397 SignatureType::ErrorNoReturn(err) => {
398 blocked(f, |f| {
399 let converter = TypeConverter::ValidatedEnum(err.inner.clone());
400 f.writeln("Ok(()) =>")?;
401 blocked(f, |f| {
402 converter.convert_to_c(
403 f,
404 &format!("{}::Ok", err.inner.name.to_upper_camel_case()),
405 "",
406 )
407 })?;
408 f.writeln("Err(err) =>")?;
409 blocked(f, |f| converter.convert_to_c(f, "err", ""))
410 })?;
411 }
412 SignatureType::ErrorWithReturn(err, result_type, _) => {
413 blocked(f, |f| {
414 let converter = TypeConverter::ValidatedEnum(err.inner.clone());
415 f.writeln("Ok(x) =>")?;
416 blocked(f, |f| {
417 if let Some(converter) = result_type.conversion() {
418 converter.convert_to_c(f, "x", "let x = ")?;
419 f.write(";")?;
420 }
421 f.writeln("out.write(x);")?;
422 converter.convert_to_c(
423 f,
424 &format!("{}::Ok", err.inner.name.to_upper_camel_case()),
425 "",
426 )
427 })?;
428 f.writeln("Err(err) =>")?;
429 blocked(f, |f| converter.convert_to_c(f, "err", ""))
430 })?;
431 }
432 }
433
434 Ok(())
435 })
436 }
437
438 fn write_interface(
439 &self,
440 f: &mut dyn Printer,
441 handle: &Interface<Validated>,
442 mode: InterfaceCategory,
443 ) -> FormattingResult<()> {
444 let interface_name = handle.name.to_upper_camel_case();
445 f.writeln("#[repr(C)]")?;
447 f.writeln("#[derive(Clone)]")?;
448 f.writeln(&format!("pub struct {interface_name}"))?;
449 blocked(f, |f| {
450 for cb in &handle.callbacks {
451 let lifetime = if cb.c_requires_lifetime() {
452 "for<'a> "
453 } else {
454 ""
455 };
456
457 f.writeln("#[allow(clippy::needless_lifetimes)]")?;
458 f.writeln(&format!(
459 "pub {name}: Option<{lifetime}extern \"C\" fn(",
460 name = cb.name,
461 lifetime = lifetime
462 ))?;
463
464 f.write(
465 &cb.arguments
466 .iter()
467 .map(|arg| format!("{}: {}", arg.name, arg.arg_type.as_c_type()))
468 .chain(std::iter::once(format!(
469 "{}: *mut std::os::raw::c_void",
470 handle.settings.interface.context_variable_name
471 )))
472 .collect::<Vec<String>>()
473 .join(", "),
474 )?;
475
476 f.write(&format!(") -> {}>,", cb.return_type.as_c_type()))?;
477 }
478
479 f.writeln(&format!(
480 "pub {}: Option<extern \"C\" fn(ctx: *mut std::os::raw::c_void)>,",
481 handle.settings.interface.destroy_func_name
482 ))?;
483
484 f.writeln(&format!(
485 "pub {}: *mut std::os::raw::c_void,",
486 handle.settings.interface.context_variable_name
487 ))?;
488 Ok(())
489 })?;
490
491 f.newline()?;
492
493 self.write_callback_helpers(
494 f,
495 mode,
496 &interface_name,
497 handle.settings.clone(),
498 handle.callbacks.iter(),
499 )?;
500
501 f.newline()?;
502
503 f.writeln(&format!("impl Drop for {interface_name}"))?;
505 blocked(f, |f| {
506 f.writeln("fn drop(&mut self)")?;
507 blocked(f, |f| {
508 f.writeln(&format!(
509 "if let Some(cb) = self.{}",
510 handle.settings.interface.destroy_func_name
511 ))?;
512 blocked(f, |f| {
513 f.writeln(&format!(
514 "cb(self.{});",
515 handle.settings.interface.context_variable_name
516 ))
517 })
518 })
519 })?;
520
521 Ok(())
522 }
523
524 fn write_callback_helpers<'b, I: Iterator<Item = &'b CallbackFunction<Validated>>>(
525 &self,
526 f: &mut dyn Printer,
527 mode: InterfaceCategory,
528 name: &str,
529 settings: Rc<LibrarySettings>,
530 callbacks: I,
531 ) -> FormattingResult<()> {
532 let generate_send_and_sync = match mode {
533 InterfaceCategory::Synchronous => false,
534 InterfaceCategory::Asynchronous => true,
535 InterfaceCategory::Future => true,
536 };
537
538 if generate_send_and_sync {
540 f.writeln(&format!("unsafe impl Send for {name} {{}}"))?;
541 f.writeln(&format!("unsafe impl Sync for {name} {{}}"))?;
542 }
543
544 f.newline()?;
545
546 f.writeln(&format!("impl {name}"))?;
548 blocked(f, |f| {
549 for callback in callbacks {
550 let lifetime = if callback.rust_requires_lifetime() {
551 "<'a>"
552 } else {
553 ""
554 };
555
556 f.writeln("#[allow(clippy::needless_lifetimes)]")?;
558 f.writeln(&format!(
559 "pub(crate) fn {name}{lifetime}(&self, ",
560 name = callback.name,
561 lifetime = lifetime
562 ))?;
563 f.write(
564 &callback
565 .arguments
566 .iter()
567 .map(|arg| format!("{}: {}", arg.name, arg.arg_type.as_rust_type()))
568 .collect::<Vec<_>>()
569 .join(", "),
570 )?;
571 f.write(")")?;
572
573 if let Some(value) = &callback.return_type.get_value() {
574 f.write(&format!(" -> Option<{}>", value.as_rust_type()))?;
575 }
576
577 blocked(f, |f| {
579 for arg in &callback.arguments {
580 if let Some(converter) = arg.arg_type.conversion() {
581 converter.convert_to_c(
582 f,
583 &arg.name,
584 &format!("let {} = ", arg.name),
585 )?;
586 f.write(";")?;
587 }
588 }
589
590 let params = &callback
591 .arguments
592 .iter()
593 .map(|arg| arg.name.to_string())
594 .chain(std::iter::once(format!(
595 "self.{}",
596 settings.interface.context_variable_name
597 )))
598 .collect::<Vec<_>>()
599 .join(", ");
600 let call = format!("cb({params})");
601
602 if let Some(v) = &callback.return_type.get_value() {
603 f.writeln(&format!("self.{}.map(|cb| ", callback.name))?;
604 blocked(f, |f| {
605 if let Some(conversion) = v.conversion() {
606 f.writeln(&format!("let _result = {call};"))?;
607 conversion.convert_from_c(f, "_result", "")
608 } else {
609 f.writeln(&call)
610 }
611 })?;
612 f.write(")")?;
613 } else {
614 f.writeln(&format!("if let Some(cb) = self.{}", callback.name))?;
615 blocked(f, |f| f.writeln(&call))?;
616 }
617
618 if callback.return_type.is_none() {
619 f.write(";")?;
620 }
621
622 Ok(())
623 })?;
624 }
625 Ok(())
626 })
627 }
628}