-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
86 lines (72 loc) · 2.6 KB
/
Copy pathbuild.rs
File metadata and controls
86 lines (72 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::path::PathBuf;
const WRAPPER_HPP: &str = "src/bindings/source/wrapper.hpp";
const BINDINGS_FILE: &str = "bindings.rs";
fn main() {
println!("cargo:rerun-if-changed={WRAPPER_HPP}");
let out_path = out_path();
generate_bindings(&out_path);
patch_serde(&out_path);
}
fn out_path() -> PathBuf {
PathBuf::from(std::env::var("OUT_DIR").unwrap()).join(BINDINGS_FILE)
}
fn generate_bindings(out_path: &PathBuf) {
bindgen::Builder::default()
.header(WRAPPER_HPP)
.enable_cxx_namespaces()
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path)
.expect("Couldn't write bindings");
}
/// Post-processes the generated bindings to add feature-gated serde support:
///
/// - Injects `#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]`
/// before every `pub struct`.
/// - Injects `#[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]`
/// before any field whose array size exceeds 32 (serde's fixed-impl limit),
/// covering the large C char arrays present in the protocol structs.
fn patch_serde(out_path: &PathBuf) {
let content = std::fs::read_to_string(out_path).expect("Could not read bindings");
let patched = content
.lines()
.flat_map(patch_line)
.collect::<Vec<_>>()
.join("\n");
std::fs::write(out_path, patched).expect("Could not write patched bindings");
}
fn patch_line(line: &str) -> Vec<String> {
let trimmed = line.trim_start();
let indent = &line[..line.len() - trimmed.len()];
if trimmed.starts_with("pub struct ") {
let serde_attr = format!(
"{indent}#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]"
);
return vec![serde_attr, line.to_string()];
}
if trimmed.starts_with("pub ") && array_size(trimmed) > 32 {
let serde_attr =
format!("{indent}#[cfg_attr(feature = \"serde\", serde(with = \"serde_arrays\"))]");
return vec![serde_attr, line.to_string()];
}
vec![line.to_string()]
}
/// Extracts the element count from a Rust array type `[Type; N]` or `[Type; Nusize]`.
/// Returns 0 if the line does not contain an array type.
fn array_size(field_line: &str) -> usize {
if let (Some(open), Some(semi), Some(close)) = (
field_line.rfind('['),
field_line.rfind(';'),
field_line.rfind(']'),
) && open < semi
&& semi < close
{
return field_line[(semi + 1)..close]
.trim()
.trim_end_matches("usize")
.trim()
.parse()
.unwrap_or(0);
}
0
}