use std::path::Path;
use rucc_diag::SourceBytes;
pub const DIR: &str = "<builtin>";
const HEADERS: &[(&str, &str)] = &[
("float.h", include_str!("../runtime/include/float.h")),
("iso646.h", include_str!("../runtime/include/iso646.h")),
("limits.h", include_str!("../runtime/include/limits.h")),
("stdalign.h", include_str!("../runtime/include/stdalign.h")),
("stdarg.h", include_str!("../runtime/include/stdarg.h")),
("stdbool.h", include_str!("../runtime/include/stdbool.h")),
("stddef.h", include_str!("../runtime/include/stddef.h")),
("stdint.h", include_str!("../runtime/include/stdint.h")),
("stdnoreturn.h", include_str!("../runtime/include/stdnoreturn.h")),
];
#[must_use]
pub fn names() -> Vec<&'static str> {
HEADERS.iter().map(|&(name, _)| name).collect()
}
#[must_use]
pub fn header(name: &str) -> Option<&'static str> {
HEADERS.iter().find(|&&(have, _)| have == name).map(|&(_, text)| text)
}
#[must_use]
pub fn read(path: &Path) -> Option<SourceBytes> {
if path.parent() != Some(Path::new(DIR)) {
return None;
}
let name = path.file_name()?.to_str()?;
header(name).map(SourceBytes::new)
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn the_shipped_headers_are_read_by_the_name_the_search_path_builds() {
let path = PathBuf::from(DIR).join("stdarg.h");
let bytes = read(&path).expect("stdarg.h is shipped");
let text = String::from_utf8(bytes.as_ref().to_vec()).expect("utf-8");
assert!(text.contains("__builtin_va_list"));
}
#[test]
fn nothing_outside_the_builtin_directory_is_answered() {
assert!(read(Path::new("/usr/include/stdarg.h")).is_none());
assert!(read(Path::new("stdarg.h")).is_none());
assert!(read(&PathBuf::from(DIR).join("stdio.h")).is_none());
assert!(read(&PathBuf::from(DIR).join("sys").join("stdarg.h")).is_none());
}
#[test]
fn the_list_is_sorted_so_that_a_new_header_has_one_place_to_go() {
let mut sorted = names();
sorted.sort_unstable();
assert_eq!(names(), sorted);
}
#[test]
fn every_header_guards_itself_under_its_own_name() {
for &(name, text) in HEADERS {
let guard = format!("__RUCC_{}", name.trim_end_matches(".h").to_uppercase());
assert!(text.contains(&guard), "{name} does not mention {guard}");
}
}
}