use anyhow::{bail, Context, Result};
use camino::Utf8PathBuf;
use cargo_metadata::Metadata;
use std::{collections::HashMap, fs};
use crate::{BindgenCrateConfigSupplier, BindgenPathsLayer};
#[derive(Debug, Clone, Default)]
pub struct CrateConfigSupplier {
paths: HashMap<String, Utf8PathBuf>,
}
impl CrateConfigSupplier {
pub fn from_cargo_metadata_command(no_deps: bool) -> Result<Self> {
let mut cmd = cargo_metadata::MetadataCommand::new();
if no_deps {
cmd.no_deps();
}
let metadata = cmd.exec().context("error running cargo metadata")?;
Ok(Self::from(metadata))
}
}
impl BindgenPathsLayer for CrateConfigSupplier {
fn get_crate_root(&self, crate_name: &str) -> Option<Utf8PathBuf> {
self.paths.get(crate_name).cloned()
}
}
impl BindgenCrateConfigSupplier for CrateConfigSupplier {
fn get_toml(&self, crate_name: &str) -> Result<Option<toml::value::Table>> {
let Some(crate_root) = self.get_crate_root(crate_name) else {
return Ok(None);
};
let config_path = crate_root.join("uniffi.toml");
if !config_path.exists() {
return Ok(None);
}
let contents = fs::read_to_string(&config_path)
.with_context(|| format!("read file: {:?}", config_path))?;
let toml = toml::de::from_str(&contents)
.with_context(|| format!("parse toml: {:?}", config_path))?;
Ok(Some(toml))
}
fn get_udl(&self, crate_name: &str, udl_name: &str) -> Result<String> {
let path = self
.get_udl_path(crate_name, udl_name)
.context(format!("No path known to UDL files for '{crate_name}'"))?;
if path.exists() {
Ok(fs::read_to_string(path)?)
} else {
bail!(format!("No UDL file found at '{path}'"));
}
}
}
impl From<Metadata> for CrateConfigSupplier {
fn from(metadata: Metadata) -> Self {
let paths: HashMap<String, Utf8PathBuf> = metadata
.packages
.iter()
.flat_map(|p| {
p.targets
.iter()
.filter(|t| {
!t.is_bin()
&& !t.is_example()
&& !t.is_test()
&& !t.is_bench()
&& !t.is_custom_build()
})
.filter_map(|t| {
p.manifest_path
.parent()
.map(|p| (t.name.replace('-', "_"), p.to_owned()))
})
})
.collect();
Self { paths }
}
}