/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{
collections::{BTreeMap, HashMap},
fs,
};
use anyhow::bail; use camino::Utf8Path; use uniffi_meta::{
create_metadata_groups, group_metadata, Metadata, MetadataGroup, MetadataGroupMap,
NamespaceMetadata,
};
/// Load metadata, component interfaces, configuration, etc. for binding generators. /// /// Bindings generators use this to load all of the inputs they need to render their code. pubstruct BindgenLoader {
bindgen_paths: BindgenPaths,
}
/// Load UniFFI metadata /// /// The metadata describes the exported interface. /// /// `source_path` can be: /// - A library file (.so, .dylib, .a, etc). Metadata will be loaded from the symbol table. /// - A UDL file. The UDL will be parsed and converted into metadata. pubfn load_metadata(&self, source_path: &Utf8Path) -> Result<MetadataGroupMap> { self.load_metadata_specialized(source_path, |_, _| Ok(None))
}
/// Load UniFFI metadata with a specialized metadata parser /// /// When loading metadata from a library, the passed-in specialized parser will be used to /// parse the data. The library path and library contents will be passed. If the parser /// returns `Ok(Some(metadata))` then this metadata will be used. If it returns `Ok(None)` than /// the default parsing will be used. /// /// Use this function when you want to support specialized library formats. pubfn load_metadata_specialized<P>(
&self,
source_path: &Utf8Path,
specialized_parser: P,
) -> Result<MetadataGroupMap> where
P: FnOnce(&Utf8Path, &[u8]) -> Result<Option<Vec<Metadata>>>,
{ ifself.is_udl(source_path) { let crate_name = crate_name_from_cargo_toml(source_path)?; letmut group = uniffi_udl::parse_udl(&fs::read_to_string(source_path)?, &crate_name)?; Self::add_checksums_to_udl_group(&mut group);
Ok(HashMap::from([(crate_name, group)]))
} else { let data = fs::read(source_path)?; let items = match specialized_parser(source_path, &data)? {
Some(items) => items,
None => macro_metadata::extract_from_bytes(&data)?,
}; letmut metadata_groups = create_metadata_groups(&items);
group_metadata(&mut metadata_groups, items)?;
for group in metadata_groups.values_mut() { let crate_name = group.namespace.crate_name.clone(); iflet Some(mut udl_group) = self.load_udl_metadata(group, &crate_name)? { Self::add_checksums_to_udl_group(&mut udl_group);
group.items.append(&mut udl_group.items); if group.namespace_docstring.is_none() {
group.namespace_docstring = udl_group.namespace_docstring;
}
};
}
Ok(metadata_groups)
}
}
/// Add checksums for metadata parsed from UDL fn add_checksums_to_udl_group(metadata_group: &mut MetadataGroup) { // Need to temporarily take items BTree set, since we're technically mutating it's contents // Each item will be added back at the bottom of the for loop. let items = std::mem::take(&mut metadata_group.items); formut meta in items { match &mut meta {
Metadata::Func(func) if func.checksum.is_none() => {
func.checksum = Some(interface::Function::checksum_from_metadata(func.clone()))
}
Metadata::Method(meth) if meth.checksum.is_none() => {
meth.checksum = Some(interface::Method::checksum_from_metadata(meth.clone()))
}
Metadata::Constructor(cons) if cons.checksum.is_none() => {
cons.checksum =
Some(interface::Constructor::checksum_from_metadata(cons.clone()))
} // Note: UDL-based callbacks don't have checksum functions, don't set the // checksum for those.
_ => (),
}
metadata_group.items.insert(meta);
}
}
/// Load a [ComponentInterface] list /// /// This converts the metadata into `ComponentInterface` instances, which contains additional /// derived information about the interface, like FFI functions signatures. pubfn load_cis(&self, metadata: MetadataGroupMap) -> Result<Vec<ComponentInterface>> { let crate_to_namespace_map: BTreeMap<String, NamespaceMetadata> = metadata
.iter()
.map(|(k, v)| (k.clone(), v.namespace.clone()))
.collect();
letmut ci_list = metadata
.into_values()
.map(|group| { let crate_name = &group.namespace.crate_name; letmut ci = ComponentInterface::new(crate_name);
ci.add_metadata(group)?;
ci.set_crate_to_namespace_map(crate_to_namespace_map.clone());
Ok(ci)
})
.collect::<Result<Vec<ComponentInterface>>>()?;
// give every CI a cloned copy of every CI - including itself for simplicity. // we end up taking n^2 copies of all ci's, but it works. let ci_list2 = ci_list.clone();
ci_list
.iter_mut()
.for_each(|ci| ci.set_all_component_interfaces(ci_list2.clone()));
Ok(ci_list)
}
fn load_udl_metadata(
&self,
group: &MetadataGroup,
crate_name: &str,
) -> Result<Option<MetadataGroup>> { let udl_items = group
.items
.iter()
.filter_map(|i| match i {
Metadata::UdlFile(meta) => Some(meta),
_ => None,
})
.collect::<Vec<_>>(); // We only support 1 UDL file per crate, for no good reason! match udl_items.len() { 0 => Ok(None), 1 => { if udl_items[0].module_path != crate_name {
bail!( "UDL is for crate '{}' but this crate name is '{}'",
udl_items[0].module_path,
crate_name
);
} let udl = self
.bindgen_paths
.get_udl(crate_name, &udl_items[0].file_stub)?; let udl_group = uniffi_udl::parse_udl(&udl, crate_name)?;
Ok(Some(udl_group))
}
n => bail!("{n} UDL files found for {crate_name}"),
}
}
/// Load a [Component] list /// /// This groups [ComponentInterface] values with configuration data from `uniffi.toml` files. /// Pass in a `parse_config` function which parses raw TOML into your language-specific config structure. /// /// Note: the TOML data will contain the entire config tree. /// You probably want to do something like /// `toml.get("bindings").and_then(|b| b.get("my-language-key"))` /// to extract the data for your bindings. pubfn load_components<P, Config>(
&self,
cis: Vec<ComponentInterface>, mut parse_config: P,
) -> Result<Vec<Component<Config>>> where
P: FnMut(&ComponentInterface, toml::Value) -> Result<Config>,
Config: Default,
{
cis.into_iter()
.map(|ci| { let toml = self.bindgen_paths.get_config(ci.crate_name())?; let config = parse_config(&ci, toml.into())?;
Ok(Component { ci, config })
})
.collect()
}
/// Load a [pipeline::initial::Root] value from the metadata pubfn load_pipeline_initial_root(
&self,
source_path: &Utf8Path,
metadata: MetadataGroupMap,
) -> Result<pipeline::initial::Root> { letmut metadata_converter = pipeline::initial::UniffiMetaConverter::default(); for metadata_group in metadata.into_values() { let table = self
.bindgen_paths
.get_config(&metadata_group.namespace.crate_name)?; if !table.is_empty() {
metadata_converter
.add_module_config_toml(metadata_group.namespace.name.clone(), table)?;
} iflet Some(docstring) = metadata_group.namespace_docstring {
metadata_converter
.add_module_docstring(metadata_group.namespace.name.clone(), docstring)?;
}
metadata_converter.add_metadata_item(Metadata::Namespace(metadata_group.namespace))?; for meta in metadata_group.items {
metadata_converter.add_metadata_item(meta)?;
}
} letmut root = metadata_converter.try_into_initial_ir()?;
root.cdylib = self.library_name(source_path).map(str::to_string);
Ok(root)
}
/// Get the basename for a source file /// /// This will remove any file extension. /// For libraries it will remove the leading `lib`. pubfn source_basename<'a>(&self, source_path: &'a Utf8Path) -> &>'a str { letmut basename = match source_path.file_stem() {
Some(stem) => stem,
None => source_path.as_str(),
}; if !self.is_udl(source_path) {
basename = match basename.strip_prefix("lib") {
Some(name) => name,
None => basename,
}
};
basename
}
/// This is the filename, without the extension and leading `lib`. pubfn library_name<'a>(&self, source_path: &'a Utf8Path) -> Option<&'a str> { let is_library = !self.is_udl(source_path);
is_library.then(|| self.source_basename(source_path))
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.