use crate::state::{relon_llvm_call_native_addr, RELON_LLVM_CALL_NATIVE_SYMBOL};
use crate::str_helpers::{
relon_llvm_f64_to_str_addr, relon_llvm_str_contains_arena_addr, RELON_LLVM_F64_TO_STR_SYMBOL,
RELON_LLVM_STR_CONTAINS_ARENA_SYMBOL,
};
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VtableSlot {
RelonStrContains = 0,
RelonCallNative = 1,
RelonF64ToStr = 2,
}
impl VtableSlot {
pub const COUNT: u32 = 3;
pub const ALL: [VtableSlot; Self::COUNT as usize] = [
VtableSlot::RelonStrContains,
VtableSlot::RelonCallNative,
VtableSlot::RelonF64ToStr,
];
pub fn symbol(self) -> &'static str {
match self {
VtableSlot::RelonStrContains => RELON_LLVM_STR_CONTAINS_ARENA_SYMBOL,
VtableSlot::RelonCallNative => RELON_LLVM_CALL_NATIVE_SYMBOL,
VtableSlot::RelonF64ToStr => RELON_LLVM_F64_TO_STR_SYMBOL,
}
}
pub fn host_addr(self) -> usize {
match self {
VtableSlot::RelonStrContains => relon_llvm_str_contains_arena_addr(),
VtableSlot::RelonCallNative => relon_llvm_call_native_addr(),
VtableSlot::RelonF64ToStr => relon_llvm_f64_to_str_addr(),
}
}
}
pub fn populate_global_mappings() -> [(&'static str, usize); VtableSlot::COUNT as usize] {
[
(
VtableSlot::RelonStrContains.symbol(),
VtableSlot::RelonStrContains.host_addr(),
),
(
VtableSlot::RelonCallNative.symbol(),
VtableSlot::RelonCallNative.host_addr(),
),
(
VtableSlot::RelonF64ToStr.symbol(),
VtableSlot::RelonF64ToStr.host_addr(),
),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slot_count_matches_variant_list() {
assert_eq!(VtableSlot::ALL.len() as u32, VtableSlot::COUNT);
}
#[test]
fn slot_indices_are_distinct_and_packed() {
assert_eq!(VtableSlot::RelonStrContains as u32, 0);
assert_eq!(VtableSlot::RelonCallNative as u32, 1);
assert_eq!(VtableSlot::RelonF64ToStr as u32, 2);
}
#[test]
fn symbols_are_stable_and_match_state_str_helpers() {
assert_eq!(
VtableSlot::RelonStrContains.symbol(),
RELON_LLVM_STR_CONTAINS_ARENA_SYMBOL
);
assert_eq!(
VtableSlot::RelonCallNative.symbol(),
RELON_LLVM_CALL_NATIVE_SYMBOL
);
assert_eq!(
VtableSlot::RelonF64ToStr.symbol(),
RELON_LLVM_F64_TO_STR_SYMBOL
);
}
#[test]
fn host_addrs_are_non_null_and_stable() {
for slot in VtableSlot::ALL {
let a = slot.host_addr();
assert_ne!(a, 0, "{slot:?} host addr must be non-null");
assert_eq!(a, slot.host_addr(), "{slot:?} host addr must be stable");
}
}
#[test]
fn populate_global_mappings_covers_every_active_slot() {
let mappings = populate_global_mappings();
assert_eq!(mappings.len() as u32, VtableSlot::COUNT);
for (sym, addr) in mappings {
assert!(!sym.is_empty(), "symbol name must be non-empty");
assert_ne!(addr, 0, "host addr must be non-null for {sym}");
}
assert_ne!(mappings[0].0, mappings[1].0);
assert_ne!(mappings[0].0, mappings[2].0);
assert_ne!(mappings[1].0, mappings[2].0);
}
}