use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn root_name(package: &str) -> Option<String> {
match crate_name(package).ok()? {
FoundCrate::Itself => Some("crate".to_string()),
FoundCrate::Name(name) => Some(name),
}
}
fn root_tokens(name: &str) -> TokenStream {
if name == "crate" {
quote!(crate)
} else {
let ident = format_ident!("{name}");
quote!(::#ident)
}
}
pub(crate) struct CrateRefs {
pub(crate) core: TokenStream,
context_roots: Vec<String>,
facade_roots: Vec<String>,
}
impl CrateRefs {
pub(crate) fn resolve() -> Self {
let core_dep = root_name("rig-core");
let facade_dep = root_name("rig");
let agent_dep = root_name("rig-agent");
let core = match (&core_dep, facade_dep.as_ref().or(agent_dep.as_ref())) {
(Some(core), _) => root_tokens(core),
(None, Some(runtime)) => {
let root = root_tokens(runtime);
quote!(#root::core)
}
(None, None) => quote!(::rig_core),
};
let facade_roots = facade_dep.iter().cloned().collect();
let context_roots = [core_dep, agent_dep, facade_dep]
.into_iter()
.flatten()
.collect();
Self {
core,
context_roots,
facade_roots,
}
}
pub(crate) fn is_context_path(&self, segments: &[String]) -> bool {
match segments {
[root, tool, context] => {
self.context_roots.iter().any(|known| known == root)
&& tool == "tool"
&& context == "ToolContext"
}
[root, agent, tool, context] => {
self.facade_roots.iter().any(|known| known == root)
&& agent == "agent"
&& tool == "tool"
&& context == "ToolContext"
}
_ => false,
}
}
}
pub(crate) fn crate_attr_string(root: &TokenStream, item: &str) -> String {
format!("{}::{item}", root.to_string().replace(' ', ""))
}