use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
enum Reachable {
Itself,
Named(String),
Absent,
}
fn lookup(package: &str) -> Reachable {
match crate_name(package) {
Ok(FoundCrate::Itself) => Reachable::Itself,
Ok(FoundCrate::Name(name)) => Reachable::Named(name),
Err(_) => Reachable::Absent,
}
}
fn root_tokens(reachable: &Reachable) -> Option<TokenStream> {
match reachable {
Reachable::Itself => Some(quote!(crate)),
Reachable::Named(name) => {
let ident = format_ident!("{name}");
Some(quote!(::#ident))
}
Reachable::Absent => None,
}
}
fn root_name(reachable: &Reachable) -> Option<String> {
match reachable {
Reachable::Itself => Some("crate".to_string()),
Reachable::Named(name) => Some(name.clone()),
Reachable::Absent => None,
}
}
pub(crate) struct CrateRefs {
pub(crate) core: TokenStream,
pub(crate) agent: Option<TokenStream>,
context_roots: Vec<String>,
facade_roots: Vec<String>,
}
impl CrateRefs {
pub(crate) fn resolve() -> Self {
let core_dep = lookup("rig-core");
let facade_dep = lookup("rig");
let agent_dep = lookup("rig-agent");
let core = root_tokens(&core_dep)
.or_else(|| root_tokens(&facade_dep).map(|root| quote!(#root::core)))
.or_else(|| root_tokens(&agent_dep).map(|root| quote!(#root::core)))
.unwrap_or_else(|| quote!(::rig_core));
let agent = root_tokens(&agent_dep).or_else(|| root_tokens(&facade_dep));
let mut context_roots = Vec::new();
let mut facade_roots = Vec::new();
if let Some(name) = root_name(&agent_dep) {
context_roots.push(name);
}
if let Some(name) = root_name(&facade_dep) {
context_roots.push(name.clone());
facade_roots.push(name);
}
Self {
core,
agent,
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(' ', ""))
}