1use std::path::Path;
23
24use rucc_diag::SourceBytes;
25
26pub const DIR: &str = "<builtin>";
32
33const HEADERS: &[(&str, &str)] = &[
39 ("arm_neon.h", include_str!("../runtime/include/arm_neon.h")),
40 ("emmintrin.h", include_str!("../runtime/include/emmintrin.h")),
41 ("float.h", include_str!("../runtime/include/float.h")),
42 ("immintrin.h", include_str!("../runtime/include/immintrin.h")),
43 ("iso646.h", include_str!("../runtime/include/iso646.h")),
44 ("limits.h", include_str!("../runtime/include/limits.h")),
45 ("mm_malloc.h", include_str!("../runtime/include/mm_malloc.h")),
46 ("mmintrin.h", include_str!("../runtime/include/mmintrin.h")),
47 ("stdalign.h", include_str!("../runtime/include/stdalign.h")),
48 ("stdarg.h", include_str!("../runtime/include/stdarg.h")),
49 ("stdatomic.h", include_str!("../runtime/include/stdatomic.h")),
50 ("stdbool.h", include_str!("../runtime/include/stdbool.h")),
51 ("stddef.h", include_str!("../runtime/include/stddef.h")),
52 ("stdint.h", include_str!("../runtime/include/stdint.h")),
53 ("stdnoreturn.h", include_str!("../runtime/include/stdnoreturn.h")),
54 ("x86intrin.h", include_str!("../runtime/include/x86intrin.h")),
55 ("xmmintrin.h", include_str!("../runtime/include/xmmintrin.h")),
56];
57
58#[must_use]
60pub fn names() -> Vec<&'static str> {
61 HEADERS.iter().map(|&(name, _)| name).collect()
62}
63
64#[must_use]
66pub fn header(name: &str) -> Option<&'static str> {
67 HEADERS.iter().find(|&&(have, _)| have == name).map(|&(_, text)| text)
68}
69
70#[must_use]
75pub fn read(path: &Path) -> Option<SourceBytes> {
76 if path.parent() != Some(Path::new(DIR)) {
77 return None;
78 }
79 let name = path.file_name()?.to_str()?;
80 header(name).map(SourceBytes::new)
81}
82
83#[cfg(test)]
84mod tests {
85 use std::path::PathBuf;
86
87 use super::*;
88
89 #[test]
90 fn the_shipped_headers_are_read_by_the_name_the_search_path_builds() {
91 let path = PathBuf::from(DIR).join("stdarg.h");
92 let bytes = read(&path).expect("stdarg.h is shipped");
93 let text = String::from_utf8(bytes.as_ref().to_vec()).expect("utf-8");
94 assert!(text.contains("__builtin_va_list"));
95 }
96
97 #[test]
98 fn nothing_outside_the_builtin_directory_is_answered() {
99 assert!(read(Path::new("/usr/include/stdarg.h")).is_none());
100 assert!(read(Path::new("stdarg.h")).is_none());
101 assert!(read(&PathBuf::from(DIR).join("stdio.h")).is_none());
102 assert!(read(&PathBuf::from(DIR).join("sys").join("stdarg.h")).is_none());
103 }
104
105 #[test]
106 fn the_list_is_sorted_so_that_a_new_header_has_one_place_to_go() {
107 let mut sorted = names();
108 sorted.sort_unstable();
109 assert_eq!(names(), sorted);
110 }
111
112 #[test]
116 fn every_header_guards_itself_under_its_own_name() {
117 for &(name, text) in HEADERS {
118 let guard = format!("__RUCC_{}", name.trim_end_matches(".h").to_uppercase());
119 assert!(text.contains(&guard), "{name} does not mention {guard}");
120 }
121 }
122}