ruda-kernel-macros 0.1.2

Compile-time bridge from Rust kernel functions to Ruda IR.
Documentation
use quote::format_ident;
use proc_macro_crate::{FoundCrate, crate_name};
use std::cell::LazyCell;
use syn::Path;

#[allow(clippy::declare_interior_mutable_const)]
const CORE_PATH: LazyCell<Path> = LazyCell::new(|| {
    resolve_core_path(|name| crate_name(name).ok())
});

fn resolve_core_path(mut lookup: impl FnMut(&str) -> Option<FoundCrate>) -> Path {
    if let Some(found) = lookup("ruda-kernel") {
        let name = match found {
            FoundCrate::Itself => "ruda_kernel".into(),
            FoundCrate::Name(name) => name,
        };
        let ident = format_ident!("{name}");
        return syn::parse_quote!(::#ident::dsl);
    }
    syn::parse_quote!(kernel_dsl)
}
#[allow(clippy::declare_interior_mutable_const)]
const FRONTEND_PATH: LazyCell<Path> = LazyCell::new(|| {
    let mut path = core_path();
    path.segments.push(format_ident!("frontend").into());
    path
});
#[allow(clippy::declare_interior_mutable_const)]
const PRELUDE_PATH: LazyCell<Path> = LazyCell::new(|| {
    let mut path = core_path();
    path.segments.push(format_ident!("prelude").into());
    path
});
#[allow(clippy::declare_interior_mutable_const)]
const TUNE_PATH: LazyCell<Path> = LazyCell::new(|| {
    let mut path = core_path();
    path.segments.push(format_ident!("tune").into());
    path
});

pub fn frontend_path() -> Path {
    #[allow(clippy::borrow_interior_mutable_const)]
    FRONTEND_PATH.clone()
}

pub fn prelude_path() -> Path {
    #[allow(clippy::borrow_interior_mutable_const)]
    PRELUDE_PATH.clone()
}

pub fn tune_path() -> Path {
    #[allow(clippy::borrow_interior_mutable_const)]
    TUNE_PATH.clone()
}

pub fn core_path() -> Path {
    #[allow(clippy::borrow_interior_mutable_const)]
    CORE_PATH.clone()
}

pub fn core_type(ty: &str) -> Path {
    let mut path = core_path();
    let ident = format_ident!("{ty}");
    path.segments.push(ident.into());
    path
}

pub fn frontend_type(ty: &str) -> Path {
    let mut path = frontend_path();
    let ident = format_ident!("{ty}");
    path.segments.push(ident.into());
    path
}

pub fn prelude_type(ty: &str) -> Path {
    let mut path = prelude_path();
    let ident = format_ident!("{ty}");
    path.segments.push(ident.into());
    path
}

pub fn tune_type(ty: &str) -> Path {
    let mut path = tune_path();
    let ident = format_ident!("{ty}");
    path.segments.push(ident.into());
    path
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn native_dependency_uses_kernel_owner() {
        let path = resolve_core_path(|name| (name == "ruda-kernel")
            .then(|| FoundCrate::Name("ruda_kernel".into())));
        assert_eq!(path, syn::parse_quote!(::ruda_kernel::dsl));
    }

    #[test]
    fn renamed_native_dependency_is_resolved() {
        let path = resolve_core_path(|name| (name == "ruda-kernel")
            .then(|| FoundCrate::Name("renamed_kernel".into())));
        assert_eq!(path, syn::parse_quote!(::renamed_kernel::dsl));
    }

    #[test]
    fn kernel_itself_uses_existing_self_alias() {
        let path = resolve_core_path(|name| (name == "ruda-kernel")
            .then_some(FoundCrate::Itself));
        assert_eq!(path, syn::parse_quote!(::ruda_kernel::dsl));
    }

    #[test]
    fn native_owner_uses_declared_dependency() {
        let path = resolve_core_path(|_| Some(FoundCrate::Name("ruda_kernel".into())));
        assert_eq!(path, syn::parse_quote!(::ruda_kernel::dsl));
    }

    #[test]
    fn existing_local_alias_remains_a_fallback() {
        assert_eq!(resolve_core_path(|_| None), syn::parse_quote!(kernel_dsl));
    }

}