//
// Syd: rock-solid application kernel
// src/kcov/api.rs: KCOV API utilities
//
// Copyright (c) 2025, 2026 Ali Polatel <alip@chesswob.org>
// SPDX-License-Identifier: GPL-3.0

// SAFETY: This module has been liberated from unsafe code!
#![forbid(unsafe_code)]

use nix::errno::Errno;

/// Constant FNV-1a 64-bit; fast, deterministic site IDs.
pub const fn kcov_hash64(s: &str) -> u64 {
    let bytes = s.as_bytes();
    let mut h: u64 = 0xcbf29ce484222325;
    let mut i: usize = 0;
    while i < bytes.len() {
        h ^= bytes[i] as u64;
        h = h.wrapping_mul(0x100000001b3);
        i += 1;
    }
    h
}

/// Record a PC edge; no-ops if not enabled (kcov handles TLS/noop)
pub fn record_pc(pc: u64) -> Result<(), Errno> {
    // Route to the single KCOV manager owned by glue.
    crate::kcov::abi::record_pc(pc)
}

//
// API macros for coverage:
// Gated by `kcov` feature and no-op when disabled.
//

/// Emit a lightweight edge at the current callsite using a stable compile-time site ID.
///
/// No-op when `kcov` feature is disabled.
#[macro_export]
macro_rules! kcov_edge {
    // Auto-site: use file:line:col
    () => {{
        const __KCOV_SITE: u64 = $crate::kcov::api::kcov_hash64(concat!(file!(), ":", line!()));
        let _ = $crate::kcov::api::record_pc(__KCOV_SITE);
    }};
    // User-specified site (any expression -> u64).
    ($site:expr) => {{
        let _ = $crate::kcov::api::record_pc(($site) as u64);
    }};
}

/// Emit an edge tagged by a human-readable string hashed at compile time.
///
/// No-op when `kcov` feature is disabled.
#[macro_export]
macro_rules! kcov_edge_site {
    // Compile-time string -> Hashed site
    ($s:literal) => {{
        const __KCOV_SITE: u64 = $crate::kcov::api::kcov_hash64($s);
        let _ = $crate::kcov::api::record_pc(__KCOV_SITE);
    }};
}

/// Record a comparison with automatic site ID.
///
/// No-op when `kcov` feature is disabled.
#[macro_export]
macro_rules! kcov_cmp {
    // Infer ip from callsite.
    ($sz:expr, $isconst:expr, $a:expr, $b:expr) => {{
        const __KCOV_SITE: u64 = $crate::kcov::api::kcov_hash64(concat!(file!(), ":", line!()));
        let _ = $crate::kcov::api::record_cmp(
            ($sz) as u8,
            ($isconst),
            ($a) as u64,
            ($b) as u64,
            __KCOV_SITE,
        );
    }};
    // Explicit site id (u64 or anything -> u64).
    ($sz:expr, $isconst:expr, $a:expr, $b:expr, $site:expr) => {{
        let _ = $crate::kcov::api::record_cmp(
            ($sz) as u8,
            ($isconst),
            ($a) as u64,
            ($b) as u64,
            ($site) as u64,
        );
    }};
}

/// Record a comparison tagged by a human-readable string hashed at compile time.
///
/// No-op when `kcov` feature is disabled.
#[macro_export]
macro_rules! kcov_cmp_site {
    // compile-time string site
    ($sz:expr, $isconst:expr, $a:expr, $b:expr, $s:literal) => {{
        const __KCOV_SITE: u64 = $crate::kcov::api::kcov_hash64($s);
        let _ = $crate::kcov::api::record_cmp(
            ($sz) as u8,
            ($isconst),
            ($a) as u64,
            ($b) as u64,
            __KCOV_SITE,
        );
    }};
}
