Better line breaking in function pointer types

The current implementation never goes to a new line when writing a
function pointer type, this can lead to long, difficult to read lines.

The goal of this change is to make that a bit more sensible.

Here is a rust code example

```
   1   │ pub type MyCallback = Option<unsafe extern "C" fn(a: usize, b: usize)>;
   2   │
   3   │ pub type MyOtherCallback =
   4   │     Option<unsafe extern "C" fn(a: usize, lot: usize, of: usize, args: usize)>;
   5   │
   6   │ #[no_mangle]
   7   │ pub extern "C" fn my_function(a: MyCallback, b: MyOtherCallback) {}
```

right when generating the corresponing C header we get

```
   1   │ #include <stdarg.h>
   2   │ #include <stdbool.h>
   3   │ #include <stdint.h>
   4   │ #include <stdlib.h>
   5   │
   6   │ typedef void (*MyCallback)(uintptr_t a, uintptr_t b);
   7   │
   8   │ typedef void (*MyOtherCallback)(uintptr_t a, uintptr_t lot, uintptr_t of, uintptr_t args);
   9   │
  10   │ void my_function(MyCallback a, MyOtherCallback b);
```

line 8 here is already quite long and will be even longer if we add new
args to `MyOtherCallback`

With the changes in this commit, we now get

```
   1   │ #include <stdarg.h>
   2   │ #include <stdbool.h>
   3   │ #include <stdint.h>
   4   │ #include <stdlib.h>
   5   │
   6   │ typedef void (*MyCallback)(uintptr_t a, uintptr_t b);
   7   │
   8   │ typedef void (*MyOtherCallback)(uintptr_t a,
   9   │                                 uintptr_t lot,
  10   │                                 uintptr_t of,
  11   │                                 uintptr_t args);
  12   │
  13   │ void my_function(MyCallback a, MyOtherCallback b);
```

which is way better and more scalable if new args are atted to
`MyOtherCallback`

The behavior is configurable using the already existing `fn.args`
configuration parameter. In this case setting it to `Horizontal` gives
back the same .h as previously and setting it to `Vertical` makes the
generator go to a new line even for the shorter `MyCallback`
declaration:

```
   1   │ #include <stdarg.h>
   2   │ #include <stdbool.h>
   3   │ #include <stdint.h>
   4   │ #include <stdlib.h>
   5   │
   6   │ typedef void (*MyCallback)(uintptr_t a,
   7   │                            uintptr_t b);
   8   │
   9   │ typedef void (*MyOtherCallback)(uintptr_t a,
  10   │                                 uintptr_t lot,
  11   │                                 uintptr_t of,
  12   │                                 uintptr_t args);
  13   │
  14   │ void my_function(MyCallback a,
  15   │                  MyOtherCallback b);
```

Closes #793
This commit is contained in:
Thibaut Lorrain 2022-10-21 16:28:42 +02:00 committed by Emilio Cobos Álvarez
parent a2bda0a1de
commit 5fd38d5417
No known key found for this signature in database
GPG Key ID: E1152D0994E4BF8A
2 changed files with 40 additions and 13 deletions

View File

@ -4,6 +4,7 @@
use std::io::Write;
use crate::bindgen::config::Layout;
use crate::bindgen::declarationtyperesolver::DeclarationType;
use crate::bindgen::ir::{ConstExpr, Function, GenericArgument, Type};
use crate::bindgen::writer::{ListType, SourceWriter};
@ -22,7 +23,7 @@ enum CDeclarator {
Array(String),
Func {
args: Vec<(Option<String>, CDecl)>,
layout_vertical: bool,
layout: Layout,
never_return: bool,
},
}
@ -79,13 +80,13 @@ impl CDecl {
cdecl
}
fn from_func(f: &Function, layout_vertical: bool, config: &Config) -> CDecl {
fn from_func(f: &Function, layout: Layout, config: &Config) -> CDecl {
let mut cdecl = CDecl::new();
cdecl.build_func(f, layout_vertical, config);
cdecl.build_func(f, layout, config);
cdecl
}
fn build_func(&mut self, f: &Function, layout_vertical: bool, config: &Config) {
fn build_func(&mut self, f: &Function, layout: Layout, config: &Config) {
let args = f
.args
.iter()
@ -98,7 +99,7 @@ impl CDecl {
.collect();
self.declarators.push(CDeclarator::Func {
args,
layout_vertical,
layout,
never_return: f.never_return,
});
self.build_type(&f.ret, false, config);
@ -182,7 +183,7 @@ impl CDecl {
});
self.declarators.push(CDeclarator::Func {
args,
layout_vertical: false,
layout: config.function.args.clone(),
never_return: *never_return,
});
self.build_type(ret, false, config);
@ -276,7 +277,7 @@ impl CDecl {
}
CDeclarator::Func {
ref args,
layout_vertical,
ref layout,
never_return,
} => {
if last_was_pointer {
@ -287,7 +288,12 @@ impl CDecl {
if args.is_empty() && config.language == Language::C {
out.write("void");
}
if layout_vertical {
fn write_vertical<F: Write>(
out: &mut SourceWriter<F>,
config: &Config,
args: &[(Option<String>, CDecl)],
) {
let align_length = out.line_length_for_align();
out.push_set_spaces(align_length);
for (i, &(ref arg_ident, ref arg_ty)) in args.iter().enumerate() {
@ -302,7 +308,13 @@ impl CDecl {
arg_ty.write(out, arg_ident, config);
}
out.pop_tab();
} else {
}
fn write_horizontal<F: Write>(
out: &mut SourceWriter<F>,
config: &Config,
args: &[(Option<String>, CDecl)],
) {
for (i, &(ref arg_ident, ref arg_ty)) in args.iter().enumerate() {
if i != 0 {
out.write(", ");
@ -314,6 +326,21 @@ impl CDecl {
arg_ty.write(out, arg_ident, config);
}
}
match layout {
Layout::Vertical => write_vertical(out, config, args),
Layout::Horizontal => write_horizontal(out, config, args),
Layout::Auto => {
if out.line_length_for_align()
+ out.measure(|out| write_horizontal(out, config, args))
> config.line_length
{
write_vertical(out, config, args)
} else {
write_horizontal(out, config, args)
}
}
}
out.write(")");
if never_return && config.language != Language::Cython {
@ -332,10 +359,10 @@ impl CDecl {
pub fn write_func<F: Write>(
out: &mut SourceWriter<F>,
f: &Function,
layout_vertical: bool,
layout: Layout,
config: &Config,
) {
CDecl::from_func(f, layout_vertical, config).write(out, Some(f.path().name()), config);
CDecl::from_func(f, layout, config).write(out, Some(f.path().name()), config);
}
pub fn write_field<F: Write>(out: &mut SourceWriter<F>, t: &Type, ident: &str, config: &Config) {

View File

@ -242,7 +242,7 @@ impl Source for Function {
}
}
}
cdecl::write_func(out, func, false, config);
cdecl::write_func(out, func, Layout::Horizontal, config);
if !func.extern_decl {
if let Some(ref postfix) = postfix {
@ -285,7 +285,7 @@ impl Source for Function {
}
}
}
cdecl::write_func(out, func, true, config);
cdecl::write_func(out, func, Layout::Vertical, config);
if !func.extern_decl {
if let Some(ref postfix) = postfix {
out.new_line();