pub const RAW_SECTION_PREFIX: &str = "thruputspecraw";
pub const RAW_SPEC_FORMAT: u32 = 5;
pub const RAW_SECTION_NAME: &str = "thruputspecrawv5";
pub const FINAL_SECTION_NAME: &str = "thruputspecv2";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpecSection {
Raw(u32),
Final,
Other,
}
pub fn classify_section(name: &str) -> SpecSection {
if name == FINAL_SECTION_NAME {
return SpecSection::Final;
}
match name
.strip_prefix(RAW_SECTION_PREFIX)
.and_then(|suffix| suffix.strip_prefix('v'))
.and_then(|digits| digits.parse::<u32>().ok())
{
Some(version) => SpecSection::Raw(version),
None => SpecSection::Other,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_section_name_matches_its_parts() {
assert_eq!(
classify_section(RAW_SECTION_NAME),
SpecSection::Raw(RAW_SPEC_FORMAT),
"RAW_SECTION_NAME must be RAW_SECTION_PREFIX + 'v' + \
RAW_SPEC_FORMAT, or producers and consumers disagree",
);
}
#[test]
fn rv32_linker_script_keeps_raw_spec_out_of_guest_memory() {
let script = include_str!("../../rv32-runtime/link/thruput-rv32.ld");
let has_line = |prefix: &str, suffix: &str| {
script.lines().any(|line| {
line.trim()
.strip_prefix(prefix)
.and_then(|rest| rest.strip_suffix(suffix))
== Some(RAW_SECTION_NAME)
})
};
assert!(
has_line("", " 0 (INFO) :") && has_line("KEEP(*(", "))"),
"thruput-rv32.ld must place {RAW_SECTION_NAME} in an (INFO) \
output section; update it alongside RAW_SPEC_FORMAT",
);
}
#[test]
fn manifest_metadata_matches_raw_spec_format() {
let manifest = include_str!("../Cargo.toml");
let declared = manifest
.lines()
.find_map(|line| line.trim().strip_prefix("raw_spec_format"))
.and_then(|rest| rest.trim().strip_prefix('='))
.and_then(|rest| rest.trim().parse::<u32>().ok())
.expect(
"Cargo.toml must carry `[package.metadata.thruput] \
raw_spec_format = <n>` so `cargo metadata` reports the \
format version this crate emits",
);
assert_eq!(
declared, RAW_SPEC_FORMAT,
"Cargo.toml's raw_spec_format must match RAW_SPEC_FORMAT",
);
}
#[test]
fn classifies_section_names() {
assert_eq!(
classify_section(RAW_SECTION_NAME),
SpecSection::Raw(RAW_SPEC_FORMAT),
);
assert_eq!(
classify_section("thruputspecrawv99"),
SpecSection::Raw(99),
);
assert_eq!(classify_section(FINAL_SECTION_NAME), SpecSection::Final);
assert_eq!(classify_section("name"), SpecSection::Other);
for name in [
"thruputspecraw",
"thruputspecrawvx",
"thruputspecrawv1x",
"thruputspecrawv-1",
] {
assert_eq!(classify_section(name), SpecSection::Other, "{name}");
}
}
}