mod context;
mod from_uniffi_meta;
mod nodes;
mod types;
use std::fs;
use anyhow::{anyhow, bail, Result};
use camino::Utf8Path;
use crate::{crate_name_from_cargo_toml, interface, macro_metadata, BindgenPaths, GlobalConfig};
pub use context::Context;
pub use from_uniffi_meta::UniffiMetaConverter;
pub use nodes::*;
pub use uniffi_pipeline::{use_prev_node, MapNode, Node};
impl Root {
pub fn from_library(
bindgen_paths: &BindgenPaths,
global_config: &GlobalConfig,
path: &Utf8Path,
crate_name: Option<String>,
) -> Result<Root> {
let mut metadata_converter = UniffiMetaConverter::default();
let mut all_metadata = macro_metadata::extract_from_library(path)?;
if let Some(crate_name) = crate_name {
all_metadata.retain(|meta| meta.module_path().split("::").next() == Some(&crate_name));
}
let mut udl_to_load = vec![];
for meta in all_metadata {
match meta {
uniffi_meta::Metadata::UdlFile(udl) => {
udl_to_load.push((
bindgen_paths.get_udl(&udl.module_path, &udl.file_stub)?,
udl.module_path,
));
}
uniffi_meta::Metadata::Namespace(namespace) => {
let table = global_config.get_config(bindgen_paths, &namespace.crate_name)?;
if !table.is_empty() {
metadata_converter.add_module_config_toml(namespace.name.clone(), table)?;
}
metadata_converter
.add_metadata_item(uniffi_meta::Metadata::Namespace(namespace))?;
}
meta => metadata_converter.add_metadata_item(meta)?,
}
}
for (udl, module_path) in udl_to_load {
Self::add_metadata_from_udl(
&mut metadata_converter,
bindgen_paths,
global_config,
&udl,
&module_path,
true,
)?;
}
let mut root = metadata_converter.try_into_initial_ir()?;
root.cdylib = calc_cdylib_name(path);
Ok(root)
}
pub fn from_udl(
bindgen_paths: &BindgenPaths,
global_config: &GlobalConfig,
path: &Utf8Path,
crate_name: Option<String>,
) -> Result<Root> {
let mut metadata_converter = UniffiMetaConverter::default();
let crate_name = match crate_name {
Some(c) => c,
None => crate_name_from_cargo_toml(path)?,
};
Self::add_metadata_from_udl(
&mut metadata_converter,
bindgen_paths,
global_config,
&fs::read_to_string(path)?,
&crate_name,
false,
)?;
metadata_converter.try_into_initial_ir()
}
fn add_metadata_from_udl(
metadata_converter: &mut UniffiMetaConverter,
bindgen_paths: &BindgenPaths,
global_config: &GlobalConfig,
udl: &str,
crate_name: &str,
library_mode: bool,
) -> Result<()> {
let metadata_group = uniffi_udl::parse_udl(udl, crate_name)?;
if let Some(docstring) = metadata_group.namespace_docstring {
metadata_converter
.add_module_docstring(metadata_group.namespace.name.clone(), docstring)?;
}
if !library_mode {
let table =
global_config.get_config(bindgen_paths, &metadata_group.namespace.crate_name)?;
if !table.is_empty() {
metadata_converter
.add_module_config_toml(metadata_group.namespace.name.clone(), table)?;
}
}
metadata_converter
.add_metadata_item(uniffi_meta::Metadata::Namespace(metadata_group.namespace))?;
for mut meta in metadata_group.items {
match &mut meta {
uniffi_meta::Metadata::Func(func) => {
func.checksum = Some(uniffi_meta::checksum(&interface::Function::from(
func.clone(),
)));
}
uniffi_meta::Metadata::Method(meth) => {
let method_object =
interface::Method::from_metadata(meth.clone(), uniffi_meta::Type::UInt8);
meth.checksum = Some(uniffi_meta::checksum(&method_object));
}
uniffi_meta::Metadata::Constructor(cons) => {
cons.checksum = Some(uniffi_meta::checksum(&interface::Constructor::from(
cons.clone(),
)));
}
_ => (),
}
metadata_converter.add_metadata_item(meta)?;
}
Ok(())
}
}
fn calc_cdylib_name(library_path: &Utf8Path) -> Option<String> {
let cdylib_extensions = [".so", ".dll", ".dylib"];
let filename = library_path.file_name()?;
let filename = filename.strip_prefix("lib").unwrap_or(filename);
for ext in cdylib_extensions {
if let Some(f) = filename.strip_suffix(ext) {
return Some(f.to_string());
}
}
None
}