Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e4b02be

Browse files
committedMay 17, 2024
Anchor regex and make test more comprehensive
Blocklist specific bitfields etc instead of whole types, and document why each one is blocklisted. Also support field renames for mangling (e.g. `type`).
1 parent 752ae6a commit e4b02be

File tree

3 files changed

+73
-35
lines changed

3 files changed

+73
-35
lines changed
 

‎ctru-sys/build.rs

+44-18
Original file line numberDiff line numberDiff line change
@@ -162,27 +162,13 @@ fn main() {
162162

163163
#[cfg(feature = "layout-tests")]
164164
{
165-
let test_file = out_dir.join("generated_layout_test.rs");
166-
test_generator
167-
// There are several bindgen-generated types that we don't want/need to check
168-
// (because they are opaque, use bitfields, anonymous structs etc.)
169-
.blocklist_type("Thread_tag")
170-
.blocklist_type("MiiData.*")
171-
.blocklist_type("ExHeader_(System|Arm11).*")
172-
.blocklist_type("FS_((Ext|System)SaveData|Program)Info")
173-
.blocklist_type("Y2RU_ConversionParams")
174-
.blocklist_field("romfs_(dir|file)", "name")
175-
// Bindgen generated types have no c++ equivalent:
176-
.blocklist_type(".*__bindgen.*")
177-
.blocklist_field(".*", "__bindgen.*")
178-
// TODO: maybe we could translate type <-> `type_` or something...
179-
.blocklist_field(".*", "type_")
180-
.generate_layout_tests(&test_file)
165+
let gen_test_file = out_dir.join("generated_layout_test.rs");
166+
generate_layout_tests(&gen_test_file, &test_generator)
181167
.unwrap_or_else(|err| panic!("Failed to generate layout tests: {err}"));
182168

183169
cpp_build::Config::from(cc_build)
184-
.compiler(&cpp)
185-
.build(test_file);
170+
.compiler(cpp)
171+
.build(gen_test_file);
186172
}
187173
}
188174

@@ -285,3 +271,43 @@ fn track_libctru_files(pacman: &Path) -> Result<(), String> {
285271

286272
Ok(())
287273
}
274+
275+
#[cfg(feature = "layout-tests")]
276+
fn generate_layout_tests(
277+
output_file: &Path,
278+
test_generator: &build::test_gen::LayoutTestGenerator,
279+
) -> Result<(), Box<dyn Error>> {
280+
// There are several bindgen-generated types/fields that we can't check:
281+
test_generator
282+
// Opaque types:
283+
.blocklist_type("MiiData")
284+
// Bitfields:
285+
.blocklist_field(
286+
"ExHeader_SystemInfoFlags",
287+
"compress_exefs_code|is_sd_application",
288+
)
289+
.blocklist_field(
290+
"ExHeader_Arm11StorageInfo",
291+
"reserved|no_romfs|use_extended_savedata_access",
292+
)
293+
.blocklist_field(
294+
"ExHeader_Arm11CoreInfo",
295+
"use_cpu_clockrate_804MHz|enable_l2c|flag[12]_unused|[no]3ds_system_mode|ideal_processor|affinity_mask",
296+
)
297+
.blocklist_field(
298+
"Y2RU_ConversionParams",
299+
"(input|output)_format|rotation|block_alignment|standard_coefficient",
300+
)
301+
.blocklist_field(
302+
"FS_(Program|(System|Ext)SaveData)Info",
303+
"mediaType"
304+
)
305+
// Variable-length arrays:
306+
.blocklist_field("romfs_(dir|file)", "name")
307+
// Bindgen anonymous types (and their associated fields):
308+
.blocklist_type(".*__bindgen.*")
309+
.blocklist_field(".*", "__bindgen.*")
310+
// Bindgen mangles `type` (a Rust keyword) to `type_`:
311+
.rename_field("type", "type_")
312+
.generate_layout_tests(output_file)
313+
}

‎ctru-sys/build/test_gen.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -71,34 +71,44 @@ impl ParseCallbacks for LayoutTestCallbacks {
7171

7272
#[derive(Debug)]
7373
pub struct LayoutTestGenerator {
74-
struct_fields: RefCell<BTreeMap<String, BTreeSet<String>>>,
7574
blocklist: RefCell<Vec<(Regex, Option<Regex>)>>,
7675
headers: RefCell<Vec<String>>,
76+
renames: RefCell<BTreeMap<String, String>>,
77+
struct_fields: RefCell<BTreeMap<String, BTreeSet<String>>>,
7778
}
7879

7980
impl LayoutTestGenerator {
8081
fn new() -> Self {
8182
Self {
82-
struct_fields: RefCell::default(),
8383
blocklist: RefCell::default(),
8484
headers: RefCell::default(),
85+
renames: RefCell::default(),
86+
struct_fields: RefCell::default(),
8587
}
8688
}
8789

8890
pub fn blocklist_type(&self, pattern: &str) -> &Self {
8991
self.blocklist
9092
.borrow_mut()
91-
.push((Regex::new(pattern).unwrap(), None));
93+
.push((Regex::new(&format!("^({pattern})$")).unwrap(), None));
9294
self
9395
}
9496

9597
pub fn blocklist_field(&self, struct_pattern: &str, field_pattern: &str) -> &Self {
9698
self.blocklist.borrow_mut().push((
97-
Regex::new(struct_pattern).unwrap(),
98-
Some(Regex::new(field_pattern).unwrap()),
99+
Regex::new(&format!("^({struct_pattern})$")).unwrap(),
100+
Some(Regex::new(&format!("^({field_pattern})$")).unwrap()),
99101
));
100102
self
101103
}
104+
105+
pub fn rename_field(&self, cpp_name: &str, rust_name: &str) -> &Self {
106+
self.renames
107+
.borrow_mut()
108+
.insert(rust_name.to_string(), cpp_name.to_string());
109+
self
110+
}
111+
102112
pub fn generate_layout_tests(
103113
&self,
104114
output_path: impl AsRef<Path>,
@@ -172,21 +182,23 @@ impl LayoutTestGenerator {
172182
continue;
173183
}
174184

175-
let field = format_ident!("{field}");
185+
let rust_field = format_ident!("{field}");
186+
let cpp_field =
187+
format_ident!("{}", self.renames.borrow().get(field).unwrap_or(field));
176188

177189
field_tests.push(build_assert_eq(
178-
&quote!(size_of!(#name::#field)),
179-
&quote!(sizeof(#name::#field)),
190+
&quote!(size_of!(#name::#rust_field)),
191+
&quote!(sizeof(#name::#cpp_field)),
180192
));
181193

182194
field_tests.push(build_assert_eq(
183-
&quote!(align_of!(#name::#field)),
184-
&quote!(alignof(#name::#field)),
195+
&quote!(align_of!(#name::#rust_field)),
196+
&quote!(alignof(#name::#cpp_field)),
185197
));
186198

187199
field_tests.push(build_assert_eq(
188-
&quote!(offset_of!(#name, #field)),
189-
&quote!(offsetof(#name, #field)),
200+
&quote!(offset_of!(#name, #rust_field)),
201+
&quote!(offsetof(#name, #cpp_field)),
190202
));
191203
}
192204
}

‎ctru-sys/tests/layout_test.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ extern crate shim_3ds;
1313

1414
use std::mem::offset_of;
1515

16-
use cpp::cpp;
17-
use ctru_sys::*;
18-
1916
fn size_of_ret<T, U>(_f: impl Fn(U) -> T) -> usize {
2017
::std::mem::size_of::<T>()
2118
}
@@ -53,13 +50,16 @@ macro_rules! align_of {
5350

5451
#[allow(non_snake_case)]
5552
#[allow(non_upper_case_globals)]
56-
mod generated {
53+
mod generated_tests {
5754
use super::*;
5855

56+
use cpp::cpp;
57+
use ctru_sys::*;
58+
5959
include!(concat!(env!("OUT_DIR"), "/generated_layout_test.rs"));
6060
}
6161

62-
mod helper_test {
62+
mod helper_tests {
6363
macro_rules! packed_struct {
6464
($name:ident, $size:literal) => {
6565
#[repr(C, packed($size))]

0 commit comments

Comments
 (0)