Skip to content

Commit ebcfba8

Browse files
committed
Use BindgenLoader for the Python pipeline
I'm liking this BindgenLoader and want to use it in more places, this is a small step towards that. Also added the `CrateConfigSupplier::from_cargo_metadata_command` utility function.
1 parent 15738c7 commit ebcfba8

File tree

6 files changed

+94
-34
lines changed

6 files changed

+94
-34
lines changed

fixtures/docstring-proc-macro/tests/test_generated_bindings.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,7 @@ mod tests {
5252

5353
let config_supplier = {
5454
use uniffi_bindgen::cargo_metadata::CrateConfigSupplier;
55-
let metadata = cargo_metadata::MetadataCommand::new()
56-
.exec()
57-
.expect("error running cargo metadata");
58-
CrateConfigSupplier::from(metadata)
55+
CrateConfigSupplier::from_cargo_metadata_command(false);
5956
};
6057

6158
uniffi_bindgen::library_mode::generate_bindings(

uniffi/src/cli/uniffi_bindgen.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use anyhow::{bail, Context, Result};
5+
use anyhow::{bail, Result};
66
use camino::Utf8PathBuf;
77
use clap::{Args, Parser, Subcommand, ValueEnum};
88
use std::fmt;
99
use uniffi_bindgen::bindings::*;
1010
use uniffi_bindgen::pipeline::initial;
11+
use uniffi_bindgen::BindgenLoader;
1112
use uniffi_pipeline::PrintOptions;
1213

1314
/// Enumeration of all foreign language targets currently supported by our CLI.
@@ -187,15 +188,10 @@ fn config_supplier(
187188
metadata_no_deps: bool,
188189
) -> Result<impl uniffi_bindgen::BindgenCrateConfigSupplier> {
189190
#[cfg(feature = "cargo-metadata")]
190-
{
191-
use uniffi_bindgen::cargo_metadata::CrateConfigSupplier;
192-
let mut cmd = cargo_metadata::MetadataCommand::new();
193-
if metadata_no_deps {
194-
cmd.no_deps();
195-
}
196-
let metadata = cmd.exec().context("error running cargo metadata")?;
197-
Ok(CrateConfigSupplier::from(metadata))
198-
}
191+
return uniffi_bindgen::cargo_metadata::CrateConfigSupplier::from_cargo_metadata_command(
192+
metadata_no_deps,
193+
);
194+
199195
#[cfg(not(feature = "cargo-metadata"))]
200196
Ok(uniffi_bindgen::EmptyCrateConfigSupplier)
201197
}
@@ -330,11 +326,14 @@ pub fn run_main() -> anyhow::Result<()> {
330326
.as_ref()
331327
.expect("--out-dir is required when generating {language} bindings");
332328
let config_supplier = config_supplier(metadata_no_deps)?;
333-
let initial_root = if library_mode {
334-
initial::Root::from_library(config_supplier, &source, crate_name.clone())?
335-
} else {
336-
initial::Root::from_udl(config_supplier, &source, crate_name.clone())?
337-
};
329+
let loader = BindgenLoader::new(&config_supplier);
330+
// Note: we ignore `library_mode` in this case, `BindgenLoader` is smart enough to
331+
// auto-detect the source type
332+
let mut metadata = loader.load_metadata(&source)?;
333+
if let Some(crate_name) = &crate_name {
334+
loader.filter_metadata_by_crate_name(&mut metadata, crate_name);
335+
}
336+
let initial_root = loader.load_pipeline_initial_root(metadata)?;
338337

339338
match language {
340339
TargetLanguage::Python => python::run_pipeline(initial_root, out_dir)?,

uniffi_bindgen/src/bindings/swift/mod.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,9 @@ impl BindingGenerator for SwiftBindingGenerator {
146146
pub fn generate_swift_bindings(options: SwiftBindingsOptions) -> Result<()> {
147147
#[cfg(feature = "cargo-metadata")]
148148
let config_supplier = {
149-
use crate::cargo_metadata::CrateConfigSupplier;
150-
use anyhow::Context;
151-
let mut cmd = cargo_metadata::MetadataCommand::new();
152-
if options.metadata_no_deps {
153-
cmd.no_deps();
154-
}
155-
let metadata = cmd.exec().context("error running cargo metadata")?;
156-
CrateConfigSupplier::from(metadata)
149+
crate::cargo_metadata::CrateConfigSupplier::from_cargo_metadata_command(
150+
options.metadata_no_deps,
151+
)?
157152
};
158153
#[cfg(not(feature = "cargo-metadata"))]
159154
let config_supplier = crate::EmptyCrateConfigSupplier;

uniffi_bindgen/src/cargo_metadata.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! Helpers for data returned by cargo_metadata. Note that this doesn't
66
//! execute cargo_metadata, just parses its output.
77
8-
use anyhow::{bail, Context};
8+
use anyhow::{bail, Context, Result};
99
use camino::Utf8PathBuf;
1010
use cargo_metadata::Metadata;
1111
use std::{collections::HashMap, fs};
@@ -17,16 +17,27 @@ pub struct CrateConfigSupplier {
1717
paths: HashMap<String, Utf8PathBuf>,
1818
}
1919

20+
impl CrateConfigSupplier {
21+
pub fn from_cargo_metadata_command(no_deps: bool) -> Result<Self> {
22+
let mut cmd = cargo_metadata::MetadataCommand::new();
23+
if no_deps {
24+
cmd.no_deps();
25+
}
26+
let metadata = cmd.exec().context("error running cargo metadata")?;
27+
Ok(Self::from(metadata))
28+
}
29+
}
30+
2031
impl BindgenCrateConfigSupplier for CrateConfigSupplier {
21-
fn get_toml(&self, crate_name: &str) -> anyhow::Result<Option<toml::value::Table>> {
32+
fn get_toml(&self, crate_name: &str) -> Result<Option<toml::value::Table>> {
2233
crate::load_toml_file(self.get_toml_path(crate_name).as_deref())
2334
}
2435

2536
fn get_toml_path(&self, crate_name: &str) -> Option<Utf8PathBuf> {
2637
self.paths.get(crate_name).map(|p| p.join("uniffi.toml"))
2738
}
2839

29-
fn get_udl(&self, crate_name: &str, udl_name: &str) -> anyhow::Result<String> {
40+
fn get_udl(&self, crate_name: &str, udl_name: &str) -> Result<String> {
3041
let path = self
3142
.paths
3243
.get(crate_name)

uniffi_bindgen/src/loader.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use uniffi_meta::{
1515
};
1616

1717
use crate::{
18-
crate_name_from_cargo_toml, macro_metadata, BindgenCrateConfigSupplier, Component,
19-
ComponentInterface, Result,
18+
crate_name_from_cargo_toml, interface, macro_metadata, pipeline, BindgenCrateConfigSupplier,
19+
Component, ComponentInterface, Result,
2020
};
2121

2222
/// Load metadata, component interfaces, configuration, etc. for binding generators.
@@ -61,7 +61,9 @@ impl<'config> BindgenLoader<'config> {
6161
match source_path.extension() {
6262
Some(ext) if ext.to_lowercase() == "udl" => {
6363
let crate_name = crate_name_from_cargo_toml(source_path)?;
64-
let group = uniffi_udl::parse_udl(&fs::read_to_string(source_path)?, &crate_name)?;
64+
let mut group =
65+
uniffi_udl::parse_udl(&fs::read_to_string(source_path)?, &crate_name)?;
66+
Self::add_checksums(&mut group);
6567
Ok(HashMap::from([(crate_name, group)]))
6668
}
6769
_ => {
@@ -88,6 +90,39 @@ impl<'config> BindgenLoader<'config> {
8890
}
8991
}
9092

93+
/// Add checksums for metadata parsed from UDL
94+
fn add_checksums(metadata_group: &mut MetadataGroup) {
95+
// Need to temporarily take items BTree set, since we're technically mutating it's contents
96+
// Each item will be added back at the bottom of the for loop.
97+
let items = std::mem::take(&mut metadata_group.items);
98+
for mut meta in items {
99+
// Make sure metadata checksums are set
100+
match &mut meta {
101+
Metadata::Func(func) => {
102+
func.checksum = Some(uniffi_meta::checksum(&interface::Function::from(
103+
func.clone(),
104+
)));
105+
}
106+
Metadata::Method(meth) => {
107+
// making a method is mildly tricky as we need a type for self.
108+
// for the purposes of a checksum we ignore self info from udl.
109+
let method_object =
110+
interface::Method::from_metadata(meth.clone(), uniffi_meta::Type::UInt8);
111+
meth.checksum = Some(uniffi_meta::checksum(&method_object));
112+
}
113+
Metadata::Constructor(cons) => {
114+
cons.checksum = Some(uniffi_meta::checksum(&interface::Constructor::from(
115+
cons.clone(),
116+
)));
117+
}
118+
// Note: UDL-based callbacks don't have checksum functions, don't set the
119+
// checksum for those.
120+
_ => (),
121+
}
122+
metadata_group.items.insert(meta);
123+
}
124+
}
125+
91126
/// Load a [ComponentInterface] list
92127
///
93128
/// This converts the metadata into `ComponentInterface` instances, which contains additional
@@ -182,6 +217,25 @@ impl<'config> BindgenLoader<'config> {
182217
.collect()
183218
}
184219

220+
/// Load a [pipeline::initial::Root] value from the metadata
221+
pub fn load_pipeline_initial_root(
222+
&self,
223+
metadata: MetadataGroupMap,
224+
) -> Result<pipeline::initial::Root> {
225+
let mut metadata_converter = pipeline::initial::UniffiMetaConverter::default();
226+
for metadata_group in metadata.into_values() {
227+
if let Some(docstring) = metadata_group.namespace_docstring {
228+
metadata_converter
229+
.add_module_docstring(metadata_group.namespace.name.clone(), docstring);
230+
}
231+
metadata_converter.add_metadata_item(Metadata::Namespace(metadata_group.namespace))?;
232+
for meta in metadata_group.items {
233+
metadata_converter.add_metadata_item(meta)?;
234+
}
235+
}
236+
metadata_converter.try_into_initial_ir()
237+
}
238+
185239
/// Get the basename for a source file
186240
///
187241
/// This will remove any file extension.
@@ -206,4 +260,8 @@ impl<'config> BindgenLoader<'config> {
206260
Some(ext) if ext.to_lowercase() == "udl"
207261
)
208262
}
263+
264+
pub fn filter_metadata_by_crate_name(&self, metadata: &mut MetadataGroupMap, crate_name: &str) {
265+
metadata.retain(|_, metadata_group| metadata_group.namespace.crate_name == crate_name)
266+
}
209267
}

uniffi_bindgen/src/pipeline/initial/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use anyhow::Result;
1717
use camino::Utf8Path;
1818

1919
use crate::{crate_name_from_cargo_toml, interface, macro_metadata, BindgenCrateConfigSupplier};
20-
use from_uniffi_meta::UniffiMetaConverter;
20+
pub use from_uniffi_meta::UniffiMetaConverter;
2121

2222
impl Root {
2323
pub fn from_library(

0 commit comments

Comments
 (0)