proxima-core 0.1.0

Foundation primitives for the proxima workspace: error, ring, arena, time, markers
Documentation
use std::env;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};

use proxima_build::Timer;
use proxima_build::sizing::SizingSource;

#[allow(clippy::expect_used)]
fn main() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR set by cargo"));
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR set by cargo");

    emit_batch_sizing(&out_dir, &manifest_dir);
    emit_time_driver_binding(&out_dir);
}

#[allow(clippy::expect_used)]
fn emit_batch_sizing(out_dir: &Path, manifest_dir: &str) {
    let source = SizingSource::load(manifest_dir, "proxima-core.toml", "PROXIMA_CORE")
        .unwrap_or_else(|err| panic!("{err}"));
    let resolve = |section: &str, key: &str| {
        source
            .resolve_int(section, key)
            .unwrap_or_else(|err| panic!("{err}"))
    };

    let recv_slot_bytes = resolve("batch", "recv_slot_bytes");
    let recv_initial_cap = resolve("batch", "recv_initial_cap");
    let send_arena_initial_bytes = resolve("batch", "send_arena_initial_bytes");
    let send_span_cap = resolve("batch", "send_span_cap");
    let signal_waiters_inline_cap = resolve("signal", "waiters_inline_cap");

    let generated = format!(
        "// auto-generated by build.rs from proxima-core.toml — do not edit\n\
         pub const BATCH_RECV_SLOT_BYTES: usize = {recv_slot_bytes};\n\
         pub const BATCH_RECV_INITIAL_CAP: usize = {recv_initial_cap};\n\
         pub const BATCH_SEND_ARENA_INITIAL_BYTES: usize = {send_arena_initial_bytes};\n\
         pub const BATCH_SEND_SPAN_CAP: usize = {send_span_cap};\n\
         pub const SIGNAL_WAITERS_INLINE_CAP: usize = {signal_waiters_inline_cap};\n"
    );

    let out_path = out_dir.join("proxima_core_sized.rs");
    fs::write(&out_path, generated)
        .unwrap_or_else(|err| panic!("write {}: {err}", out_path.display()));
}

// folded in from the former proxima-time crate's own build.rs — binds
// `time::BOUND_DRIVER` at link time, either from a `PROXIMA_PROFILE`'s
// `timer` axis or from whichever `time-driver-*` cargo feature is active.
#[allow(clippy::expect_used)]
fn emit_time_driver_binding(out_dir: &Path) {
    // the external (link-injected) driver's module is compiled either by its
    // cargo feature OR when a profile's timer axis selects it — so a profile
    // alone is a self-contained switch (no cargo feature needed). declare the
    // cfg so check-cfg doesn't warn.
    println!("cargo:rustc-check-cfg=cfg(proxima_external_driver)");

    let driver_path = if env::var("PROXIMA_PROFILE").is_ok() {
        let resolved = proxima_build::resolve_profile().expect("resolve proxima profile");
        let timer = resolved.profile.timer_kind().expect("resolve timer axis");
        proxima_build::emit_timer_binding(&resolved).expect("emit proxima_time_bound_driver.rs");
        proxima_build::emit_rerun_directives(&resolved);
        timer.driver_path().to_string()
    } else {
        let driver = default_driver_path();
        let path = out_dir.join("proxima_time_bound_driver.rs");
        let mut file = fs::File::create(&path).expect("create proxima_time_bound_driver.rs");
        write!(
            file,
            "// auto-generated default binding (PROXIMA_PROFILE unset)\n\
             pub static BOUND_DRIVER: &dyn crate::time::Driver = &{driver};\n"
        )
        .expect("write default binding");
        driver.to_string()
    };

    // the external driver's module references prime's extern symbols; only
    // compile it when it is the bound driver, so std-thread / unbound builds
    // don't declare unresolved symbols.
    if driver_path == Timer::PrimeWheel.driver_path() {
        println!("cargo:rustc-cfg=proxima_external_driver");
    }

    println!("cargo:rerun-if-env-changed=PROXIMA_PROFILE");
    println!("cargo:rerun-if-env-changed=PROXIMA_TIMER");
}

/// Driver path for the `PROXIMA_PROFILE`-unset case, chosen by the active
/// `time-driver-*` cargo feature. Cargo sets `CARGO_FEATURE_<UPPER_SNAKE>=1`
/// for each active feature.
fn default_driver_path() -> &'static str {
    if env::var("CARGO_FEATURE_TIME_DRIVER_PRIME_WHEEL").is_ok() {
        Timer::PrimeWheel.driver_path()
    } else if env::var("CARGO_FEATURE_TIME_DRIVER_STD_THREAD").is_ok() {
        Timer::StdThread.driver_path()
    } else if env::var("CARGO_FEATURE_TIME_DRIVER_MOCK").is_ok() {
        Timer::Mock.driver_path()
    } else if env::var("CARGO_FEATURE_TIME_DRIVER_WASM").is_ok()
        && env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("wasm32")
    {
        // wasm driver's DRIVER static is itself wasm32-gated; only bind it
        // when actually compiling for wasm so non-wasm verification builds
        // with the feature on still link the unbound fallback.
        "crate::time::drivers::wasm::DRIVER"
    } else {
        // no driver feature → fall back to the panics-on-use unbound driver.
        // The crate still links (so downstream alloc-only / thumbv7m
        // verification builds succeed); any actual call to
        // Delay/Sleep/Timeout/Interval at runtime panics with a clear message
        // about the missing driver configuration.
        "crate::time::drivers::unbound::DRIVER"
    }
}